From 28d4d7ea3f3ad01bcd2ab35382cb7b3728a84d78 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 7 Oct 2012 20:00:55 +0200 Subject: [PATCH 0001/1483] Manually convert last changes in branch to upstream/master. Regular merge attempt resulted in everything being overwritten by fast-forward merging. - Remove check for 255 master/plugin files. --- apps/openmw/engine.cpp | 29 +++++++++++----- apps/openmw/engine.hpp | 8 +++-- apps/openmw/main.cpp | 21 ++++++------ apps/openmw/mwrender/terrain.cpp | 31 +++++++++++++---- apps/openmw/mwrender/terrain.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 33 ++++++++++++++---- 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 | 56 +++++++++++++++++++++++++------ components/esm_store/store.cpp | 9 +++++ 12 files changed, 155 insertions(+), 47 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b86923a1d3..a02dbf1d63 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -212,18 +212,31 @@ 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 ("."); + 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"; } } @@ -331,8 +344,8 @@ void OMW::Engine::go() MWGui::CursorReplace replacer; // Create the world - mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); + mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, + mResDir, mCfgMgr.getCachePath(), 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 57402c91e2..7fd27b36b9 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -64,7 +64,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; @@ -122,9 +123,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 5c2ba2f80b..c2b8d75596 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -224,18 +224,19 @@ 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()) + // Removed check for 255 files, which would be the hard-coded limit in Morrowind. + // I'll keep the following variable in, maybe we can use it for somethng different. + int cnt = master.size() + plugin.size(); + + // Prepare loading master/plugin files (i.e. send filenames to engine) + for (std::vector::size_type i = 0; i < master.size(); i++) { - std::cout << "Ignoring plugin files (plugins not yet supported)." << std::endl; + engine.addMaster(master[i]); + } + for (std::vector::size_type i = 0; i < plugin.size(); i++) + { + engine.addPlugin(plugin[i]); } // startup-settings diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 691e7c4af3..e39cdd1506 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); + numTextures, indexes, land->plugin); if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL) { @@ -200,8 +200,13 @@ 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"); @@ -214,12 +219,20 @@ 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); + // This is a quick hack to prevent the program from trying to fetch textures + // from a neighboring cell, which might originate from a different plugin, + // and use a separate texture palette. Right now, we simply cast it to the + // default texture (i.e. 0). + if (idx > num) + idx = 0; + ltexIndexes.insert(idx); } } @@ -231,7 +244,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 ) { @@ -244,8 +257,12 @@ 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 && - "LAND.VTEX must be within the bounds of the LTEX array"); + // NOTE: using the quick hack above, we should no longer end up with textures indices + // that are out of bounds. However, I haven't updated the test to a multi-palette + // system yet. We probably need more work here, so we skip it for now. + + //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 ) @@ -254,7 +271,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 c83d96cf47..484a0dbe3a 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -75,7 +75,7 @@ namespace MWRender{ 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); /** * 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 38063b0519..dd3717f972 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -164,7 +164,8 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, + const std::vector& master, const std::vector& plugins, + const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mNextDynamicRecord (0), mCells (mStore, mEsm), @@ -177,14 +178,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 + mEsm.setEncoding(encoding); + mEsm.open (masterPath.string()); + mEsm.setIndex(idx); + 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 ESM file and loads a sample cell - mEsm.setEncoding(encoding); - mEsm.open (masterPath.string()); - mStore.load (mEsm); + // This parses the ESP file + mEsm.setEncoding(encoding); + mEsm.open (pluginPath.string()); + mEsm.setIndex(idx); + mStore.load (mEsm); + } mPlayer = new MWWorld::Player (mStore.npcs.find ("player"), *this); mRendering->attachCameraTo(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 90cd2151b6..52bda67495 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -96,7 +96,8 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, + const std::vector& master, const std::vector& plugins, + const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, 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 66c0710a68..afa6da2134 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -189,6 +189,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 05cadae7f9..1016170711 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 ebc314a280..898134d724 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 ffecfc8de0..42597bea4b 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. Plugin files support this, so we need to do this, too. + 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,63 @@ 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() { - // More than enough to hold Morrowind.esm. - ltex.reserve(128); + ltex.push_back(LandTextureList()); + LandTextureList <exl = ltex[0]; + // More than enough to hold Morrowind.esm. Extra lists for plugins will we + // added on-the-fly in a different method. + 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); } + // "getSize" returns the number of individual terrain palettes. + // "getSizePlugin" returns the number of land textures in a specific palette. 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 {} - void load(ESMReader &esm, const std::string &id) + 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; + } + + // Load all terrain palettes at the same size. Inherited virtual function + // from "RecList". Mostly useless, because we need the implementation + // above this one. + 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 c676601e54..d13cd373d3 100644 --- a/components/esm_store/store.cpp +++ b/components/esm_store/store.cpp @@ -67,6 +67,15 @@ void ESMStore::load(ESMReader &esm) { // Load it std::string id = esm.getHNOString("NAME"); + // ... unless it got deleted! This means that the following record + // has been deleted, and trying to load it using standard assumptions + // on the structure will (probably) fail. + 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 7f77bf76c7bc3e12fce4879b21612a6d49101fb7 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Tue, 6 Nov 2012 22:13:19 +0100 Subject: [PATCH 0002/1483] - Add support for multiple esm contexts in cell store. This will allow to generate references from multiple esX files. Currently, only the first context is used. - Add many TODOs to mark points where more work is required to fully implement this feature. --- apps/openmw/mwworld/cellstore.cpp | 128 +++++++++++++++++------------- apps/openmw/mwworld/cellstore.hpp | 4 + components/esm/loadcell.cpp | 12 ++- components/esm/loadcell.hpp | 3 +- extern/shiny | 2 +- 5 files changed, 89 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index fcdec1e7f0..322b43a00d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -45,23 +45,32 @@ namespace MWWorld { assert (cell); - if (cell->mContext.filename.empty()) + if (cell->mContextList.size() == 0) return; // this is a dynamically generated cell -> skipping. - // Reopen the ESM reader and seek to the right position. - cell->restore (esm); - - ESM::CellRef ref; - - // Get each reference in turn - while (cell->getNextRef (esm, ref)) + // Load references from all plugins that do something with this cell. + // HACK: only use first entry for now, full support requires some more work + //for (int i = 0; i < cell->mContextList.size(); i++) + for (int i = 0; i < 1; i++) { - std::string lowerCase; + // Reopen the ESM reader and seek to the right position. + // TODO: we will need to intoduce separate "esm"s, one per plugin! + cell->restore (esm); - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + ESM::CellRef ref; - mIds.push_back (lowerCase); + // Get each reference in turn + while (cell->getNextRef (esm, ref)) + { + std::string lowerCase; + + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + // TODO: support deletion / moving references out of the cell. no simple "push_back", + // but see what the plugin wants to do. + mIds.push_back (lowerCase); + } } std::sort (mIds.begin(), mIds.end()); @@ -71,57 +80,64 @@ namespace MWWorld { assert (cell); - if (cell->mContext.filename.empty()) + if (cell->mContextList.size() == 0) return; // this is a dynamically generated cell -> skipping. - // Reopen the ESM reader and seek to the right position. - cell->restore(esm); - - ESM::CellRef ref; - - // Get each reference in turn - while(cell->getNextRef(esm, ref)) + // Load references from all plugins that do something with this cell. + // HACK: only use first entry for now, full support requires some more work + //for (int i = 0; i < cell->mContextList.size(); i++) + for (int i = 0; i < 1; i++) { - std::string lowerCase; + // Reopen the ESM reader and seek to the right position. + // TODO: we will need to intoduce separate "esm"s, one per plugin! + cell->restore(esm); - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + ESM::CellRef ref; - int rec = store.find(ref.mRefID); - - ref.mRefID = lowerCase; - - /* We can optimize this further by storing the pointer to the - record itself in store.all, so that we don't need to look it - up again here. However, never optimize. There are infinite - opportunities to do that later. - */ - switch(rec) + // Get each reference in turn + while(cell->getNextRef(esm, ref)) { - case ESM::REC_ACTI: activators.find(ref, store.activators); break; - case ESM::REC_ALCH: potions.find(ref, store.potions); break; - case ESM::REC_APPA: appas.find(ref, store.appas); break; - case ESM::REC_ARMO: armors.find(ref, store.armors); break; - case ESM::REC_BOOK: books.find(ref, store.books); break; - case ESM::REC_CLOT: clothes.find(ref, store.clothes); break; - case ESM::REC_CONT: containers.find(ref, store.containers); break; - case ESM::REC_CREA: creatures.find(ref, store.creatures); break; - case ESM::REC_DOOR: doors.find(ref, store.doors); break; - case ESM::REC_INGR: ingreds.find(ref, store.ingreds); break; - case ESM::REC_LEVC: creatureLists.find(ref, store.creatureLists); break; - case ESM::REC_LEVI: itemLists.find(ref, store.itemLists); break; - case ESM::REC_LIGH: lights.find(ref, store.lights); break; - case ESM::REC_LOCK: lockpicks.find(ref, store.lockpicks); break; - case ESM::REC_MISC: miscItems.find(ref, store.miscItems); break; - case ESM::REC_NPC_: npcs.find(ref, store.npcs); break; - case ESM::REC_PROB: probes.find(ref, store.probes); break; - case ESM::REC_REPA: repairs.find(ref, store.repairs); break; - case ESM::REC_STAT: statics.find(ref, store.statics); break; - case ESM::REC_WEAP: weapons.find(ref, store.weapons); break; + std::string lowerCase; - case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break; - default: - std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + int rec = store.find(ref.mRefID); + + ref.mRefID = lowerCase; + + /* We can optimize this further by storing the pointer to the + record itself in store.all, so that we don't need to look it + up again here. However, never optimize. There are infinite + opportunities to do that later. + */ + switch(rec) + { + case ESM::REC_ACTI: activators.find(ref, store.activators); break; + case ESM::REC_ALCH: potions.find(ref, store.potions); break; + case ESM::REC_APPA: appas.find(ref, store.appas); break; + case ESM::REC_ARMO: armors.find(ref, store.armors); break; + case ESM::REC_BOOK: books.find(ref, store.books); break; + case ESM::REC_CLOT: clothes.find(ref, store.clothes); break; + case ESM::REC_CONT: containers.find(ref, store.containers); break; + case ESM::REC_CREA: creatures.find(ref, store.creatures); break; + case ESM::REC_DOOR: doors.find(ref, store.doors); break; + case ESM::REC_INGR: ingreds.find(ref, store.ingreds); break; + case ESM::REC_LEVC: creatureLists.find(ref, store.creatureLists); break; + case ESM::REC_LEVI: itemLists.find(ref, store.itemLists); break; + case ESM::REC_LIGH: lights.find(ref, store.lights); break; + case ESM::REC_LOCK: lockpicks.find(ref, store.lockpicks); break; + case ESM::REC_MISC: miscItems.find(ref, store.miscItems); break; + case ESM::REC_NPC_: npcs.find(ref, store.npcs); break; + case ESM::REC_PROB: probes.find(ref, store.probes); break; + case ESM::REC_REPA: repairs.find(ref, store.repairs); break; + case ESM::REC_STAT: statics.find(ref, store.statics); break; + case ESM::REC_WEAP: weapons.find(ref, store.weapons); break; + + case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break; + default: + std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; + } } } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 32ab6e07b9..fd739b5651 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -62,6 +62,10 @@ namespace MWWorld if(obj == NULL) throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + // TODO: this line must be modified for multiple plugins and moved references. + // This means: no simple "push back", but search for an existing reference with + // this ID first! If it exists, merge data into this list instead of just adding it. + // I'll probably generate a separate method jist for this. list.push_back(LiveRef(ref, obj)); } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 97ce177753..65c9c23e7a 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "esmreader.hpp" #include "esmwriter.hpp" @@ -111,7 +112,7 @@ void Cell::load(ESMReader &esm) } // Save position of the cell references and move on - mContext = esm.getContext(); + mContextList.push_back(esm.getContext()); esm.skipRecord(); } @@ -148,7 +149,8 @@ void Cell::save(ESMWriter &esm) void Cell::restore(ESMReader &esm) const { - esm.restoreContext(mContext); + // TODO: support all contexts in the list! + esm.restoreContext(mContextList[0]); } std::string Cell::getDescription() const @@ -167,6 +169,12 @@ std::string Cell::getDescription() const bool Cell::getNextRef(ESMReader &esm, CellRef &ref) { + // TODO: Add support for moved references. References moved without crossing a cell boundary simply + // overwrite old data. References moved across cell boundaries are using a different set of keywords, + // and I'll have to think more about how this can be done. + // TODO: Add support for multiple plugins. This requires a tricky renaming scheme for "ref.mRefnum". + // I'll probably add something to "ESMReader", we will need one per plugin anyway. + // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index fbd7c04562..9511ae0e74 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -2,6 +2,7 @@ #define OPENMW_ESM_CELL_H #include +#include #include "esmcommon.hpp" #include "defs.hpp" @@ -120,7 +121,7 @@ struct Cell // Optional region name for exterior and quasi-exterior cells. std::string mRegion; - ESM_Context mContext; // File position + std::vector mContextList; // File position; multiple positions for multiple plugin support DATAstruct mData; AMBIstruct mAmbi; float mWater; // Water level diff --git a/extern/shiny b/extern/shiny index f17c4ebab0..4750676ac4 160000 --- a/extern/shiny +++ b/extern/shiny @@ -1 +1 @@ -Subproject commit f17c4ebab0e7a1f3bbb25fd9b3dbef2bd742536a +Subproject commit 4750676ac46a7aaa86bca53dc68c5a1ba11f3bc1 From 42eefaf36ff371d8bdecdca54e5aa26269d7ba6b Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 10 Nov 2012 21:43:41 +0100 Subject: [PATCH 0003/1483] - Add support for loading references from multiple esm/esp files. Full reference ID mangling coming soon (currently, moved references are simply cloned). - Reference loader now (partially) supports MVRF tag. --- apps/esmtool/esmtool.cpp | 5 ++++- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/cells.cpp | 3 ++- apps/openmw/mwworld/cells.hpp | 5 +++-- apps/openmw/mwworld/cellstore.cpp | 34 +++++++++++++++---------------- apps/openmw/mwworld/cellstore.hpp | 10 ++++----- apps/openmw/mwworld/worldimp.cpp | 24 ++++++++++++++-------- apps/openmw/mwworld/worldimp.hpp | 4 ++-- components/esm/esmcommon.hpp | 4 ++++ components/esm/esmreader.hpp | 2 +- components/esm/loadcell.cpp | 31 +++++++++++++++++++++------- components/esm/loadcell.hpp | 2 +- components/esm_store/reclists.hpp | 19 +++++++++++++++-- 13 files changed, 95 insertions(+), 50 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 4f6d9dbfc0..25c4f3a7a9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -220,7 +220,10 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) bool save = (info.mode == "clone"); // Skip back to the beginning of the reference list - cell.restore(esm); + // FIXME: Changes to the references backend required to support multiple plugins have + // almost certainly broken this following line. I'll leave it as is for now, so that + // the compiler does not complain. + cell.restore(esm, 0); // Loop through all the references ESM::CellRef ref; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6710fc68b0..06c3002c7e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -106,7 +106,7 @@ namespace MWBase virtual const ESMS::ESMStore& getStore() const = 0; - virtual ESM::ESMReader& getEsmReader() = 0; + virtual std::vector& getEsmReader() = 0; virtual MWWorld::LocalScripts& getLocalScripts() = 0; diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index e5a38d4be1..e49835f412 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -85,7 +85,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS return ptr; } -MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader) +MWWorld::Cells::Cells (const ESMS::ESMStore& store, std::vector& reader) : mStore (store), mReader (reader), mIdCache (20, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable mIdCacheIndex (0) @@ -120,6 +120,7 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) if (result->second.mState!=Ptr::CellStore::State_Loaded) { + // Multiple plugin support for landscape data is much easier than for references. The last plugin wins. result->second.load (mStore, mReader); fillContainers (result->second); } diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 3e13831665..3941399f89 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -2,6 +2,7 @@ #define GAME_MWWORLD_CELLS_H #include +#include #include #include "ptr.hpp" @@ -22,7 +23,7 @@ namespace MWWorld class Cells { const ESMS::ESMStore& mStore; - ESM::ESMReader& mReader; + std::vector& mReader; std::map mInteriors; std::map, CellStore> mExteriors; std::vector > mIdCache; @@ -39,7 +40,7 @@ namespace MWWorld public: - Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader); + Cells (const ESMS::ESMStore& store, std::vector& reader); ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole /// world diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 322b43a00d..91c0afe26f 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -16,7 +16,7 @@ namespace MWWorld mWaterLevel = cell->mWater; } - void CellStore::load (const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::load (const ESMS::ESMStore &store, std::vector &esm) { if (mState!=State_Loaded) { @@ -31,7 +31,7 @@ namespace MWWorld } } - void CellStore::preload (const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::preload (const ESMS::ESMStore &store, std::vector &esm) { if (mState==State_Unloaded) { @@ -41,7 +41,7 @@ namespace MWWorld } } - void CellStore::listRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::listRefs(const ESMS::ESMStore &store, std::vector &esm) { assert (cell); @@ -49,26 +49,24 @@ namespace MWWorld return; // this is a dynamically generated cell -> skipping. // Load references from all plugins that do something with this cell. - // HACK: only use first entry for now, full support requires some more work - //for (int i = 0; i < cell->mContextList.size(); i++) - for (int i = 0; i < 1; i++) + for (size_t i = 0; i < cell->mContextList.size(); i++) { // Reopen the ESM reader and seek to the right position. - // TODO: we will need to intoduce separate "esm"s, one per plugin! - cell->restore (esm); + int index = cell->mContextList.at(i).index; + cell->restore (esm[index], i); ESM::CellRef ref; // Get each reference in turn - while (cell->getNextRef (esm, ref)) + while (cell->getNextRef (esm[index], ref)) { std::string lowerCase; std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: support deletion / moving references out of the cell. no simple "push_back", - // but see what the plugin wants to do. + // TODO: Fully support deletion / moving references out of the cell. no simple "push_back", + // but make sure that the reference exists only once. mIds.push_back (lowerCase); } } @@ -76,7 +74,7 @@ namespace MWWorld std::sort (mIds.begin(), mIds.end()); } - void CellStore::loadRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::loadRefs(const ESMS::ESMStore &store, std::vector &esm) { assert (cell); @@ -84,24 +82,24 @@ namespace MWWorld return; // this is a dynamically generated cell -> skipping. // Load references from all plugins that do something with this cell. - // HACK: only use first entry for now, full support requires some more work - //for (int i = 0; i < cell->mContextList.size(); i++) - for (int i = 0; i < 1; i++) + for (size_t i = 0; i < cell->mContextList.size(); i++) { // Reopen the ESM reader and seek to the right position. - // TODO: we will need to intoduce separate "esm"s, one per plugin! - cell->restore(esm); + int index = cell->mContextList.at(i).index; + cell->restore (esm[index], i); ESM::CellRef ref; // Get each reference in turn - while(cell->getNextRef(esm, ref)) + while(cell->getNextRef(esm[index], ref)) { std::string lowerCase; std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); + // TODO: Fully support deletion / moving references out of the cell. No simple loading, + // but make sure that the reference exists only once. Current code clones references. int rec = store.find(ref.mRefID); ref.mRefID = lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index fd739b5651..69c4cf9b4b 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include "refdata.hpp" @@ -126,9 +126,9 @@ namespace MWWorld CellRefList statics; CellRefList weapons; - void load (const ESMS::ESMStore &store, ESM::ESMReader &esm); + void load (const ESMS::ESMStore &store, std::vector &esm); - void preload (const ESMS::ESMStore &store, ESM::ESMReader &esm); + void preload (const ESMS::ESMStore &store, std::vector &esm); /// Call functor (ref) for each reference. functor must return a bool. Returning /// false will abort the iteration. @@ -187,9 +187,9 @@ namespace MWWorld } /// Run through references and store IDs - void listRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm); + void listRefs(const ESMS::ESMStore &store, std::vector &esm); - void loadRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm); + void loadRefs(const ESMS::ESMStore &store, std::vector &esm); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6cf831b534..bbc44f5e10 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -179,6 +179,8 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering); int idx = 0; + // NOTE: We might need to reserve one more for the running game / save. + mEsm.resize(master.size() + plugins.size()); for (std::vector::size_type i = 0; i < master.size(); i++, idx++) { boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); @@ -186,10 +188,12 @@ namespace MWWorld std::cout << "Loading ESM " << masterPath.string() << "\n"; // This parses the ESM file - mEsm.setEncoding(encoding); - mEsm.open (masterPath.string()); - mEsm.setIndex(idx); - mStore.load (mEsm); + ESM::ESMReader lEsm; + lEsm.setEncoding(encoding); + lEsm.open (masterPath.string()); + lEsm.setIndex(idx); + mEsm[idx] = lEsm; + mStore.load (mEsm[idx]); } for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) @@ -199,10 +203,12 @@ namespace MWWorld std::cout << "Loading ESP " << pluginPath.string() << "\n"; // This parses the ESP file - mEsm.setEncoding(encoding); - mEsm.open (pluginPath.string()); - mEsm.setIndex(idx); - mStore.load (mEsm); + ESM::ESMReader lEsm; + lEsm.setEncoding(encoding); + lEsm.open (pluginPath.string()); + lEsm.setIndex(idx); + mEsm[idx] = lEsm; + mStore.load (mEsm[idx]); } mPlayer = new MWWorld::Player (mStore.npcs.find ("player"), *this); @@ -282,7 +288,7 @@ namespace MWWorld return mStore; } - ESM::ESMReader& World::getEsmReader() + std::vector& World::getEsmReader() { return mEsm; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c8c56f130e..ffb2137c7b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -55,7 +55,7 @@ namespace MWWorld MWWorld::Scene *mWorldScene; MWWorld::Player *mPlayer; - ESM::ESMReader mEsm; + std::vector mEsm; ESMS::ESMStore mStore; LocalScripts mLocalScripts; MWWorld::Globals *mGlobalVariables; @@ -127,7 +127,7 @@ namespace MWWorld virtual const ESMS::ESMStore& getStore() const; - virtual ESM::ESMReader& getEsmReader(); + virtual std::vector& getEsmReader(); virtual LocalScripts& getLocalScripts(); diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index e0c5c08afe..d61564c676 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -113,6 +113,10 @@ struct ESM_Context size_t leftFile; NAME recName, subName; HEDRstruct header; + // When working with multiple esX files, we will generate lists of all files that + // actually contribute to a specific cell. Therefore, we need to store the index + // of the file belonging to this contest. See CellStore::(list/load)refs for details. + int index; // True if subName has been read but not used. bool subCached; diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 96b164d5e9..f09442a577 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -81,7 +81,7 @@ public: // 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;} + void setIndex(const int index) {idx = index; mCtx.index = index;} const int getIndex() {return idx;} /************************************************************************* diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 65c9c23e7a..beedd3cacf 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -113,6 +113,8 @@ void Cell::load(ESMReader &esm) // Save position of the cell references and move on mContextList.push_back(esm.getContext()); + if (mContextList.size() > 1) + std::cout << "found two plugins" << std::endl; esm.skipRecord(); } @@ -147,10 +149,9 @@ void Cell::save(ESMWriter &esm) esm.writeHNT("NAM0", mNAM0); } -void Cell::restore(ESMReader &esm) const +void Cell::restore(ESMReader &esm, int iCtx) const { - // TODO: support all contexts in the list! - esm.restoreContext(mContextList[0]); + esm.restoreContext(mContextList[iCtx]); } std::string Cell::getDescription() const @@ -169,15 +170,28 @@ std::string Cell::getDescription() const bool Cell::getNextRef(ESMReader &esm, CellRef &ref) { - // TODO: Add support for moved references. References moved without crossing a cell boundary simply - // overwrite old data. References moved across cell boundaries are using a different set of keywords, - // and I'll have to think more about how this can be done. // TODO: Add support for multiple plugins. This requires a tricky renaming scheme for "ref.mRefnum". // I'll probably add something to "ESMReader", we will need one per plugin anyway. // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; - + + if (esm.isNextSub("MVRF")) { + // Moved existing reference across cell boundaries, so interpret the blocks correctly. + // FIXME: Right now, we don't do anything with this data. This might result in weird behaviour, + // where a moved reference does not appear because the owning cell (i.e. this cell) is not + // loaded in memory. + int movedRefnum = 0; + int destCell[2]; + esm.getHT(movedRefnum); + esm.getHNT(destCell, "CNDT"); + // TODO: Figure out what happens when a reference has moved into an interior cell. This might + // be required for NPCs following the player. + } + // If we have just parsed a MVRF entry, there should be a regular FRMR entry following right there. + // With the exception that this bock technically belongs to a different cell than this one. + // TODO: Figure out a way to handle these weird references that do not belong to this cell. + // This may require some not-so-small behing-the-scenes updates. esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); @@ -228,6 +242,9 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. + // Update: Well, maybe not completely useless. This might actually be + // number_of_references + number_of_references_moved_here_Across_boundaries, + // and could be helpful for collecting these weird moved references. ref.mNam0 = 0; if (esm.isNextSub("NAM0")) { diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 9511ae0e74..ccfdcadd87 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -152,7 +152,7 @@ struct Cell // somewhere other than the file system, you need to pre-open the // ESMReader, and the filename must match the stored filename // exactly. - void restore(ESMReader &esm) const; + void restore(ESMReader &esm, int iCtx) const; std::string getDescription() const; ///< Return a short string describing the cell (mostly used for debugging/logging purpose) diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index eac1b5b724..44b7e6569e 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -496,6 +496,11 @@ namespace ESMS { count++; + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded! So first, proceed as usual. + // All cells have a name record, even nameless exterior cells. ESM::Cell *cell = new ESM::Cell; cell->mName = id; @@ -505,12 +510,22 @@ namespace ESMS if(cell->mData.mFlags & ESM::Cell::Interior) { - // Store interior cell by name + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(searchInt(id)); + if (oldcell) { + cell->mContextList.push_back(oldcell->mContextList.at(0)); + delete oldcell; + } intCells[id] = cell; } else { - // Store exterior cells by grid position + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(searchExt(cell->getGridX(), cell->getGridY())); + if (oldcell) { + cell->mContextList.push_back(oldcell->mContextList.at(0)); + delete oldcell; + } extCells[std::make_pair (cell->mData.mX, cell->mData.mY)] = cell; } } From 2175f13b67e9075455bc944b0e32cdd0cb9b5ceb Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 17 Nov 2012 00:21:51 +0100 Subject: [PATCH 0004/1483] - Add tracking for dependencies between plugins. - Add reference number mangling required for moving references around. --- apps/openmw/mwworld/worldimp.cpp | 6 ++++-- components/esm/esmcommon.hpp | 1 + components/esm/esmreader.cpp | 25 +++++++++++++++++++++++++ components/esm/esmreader.hpp | 3 +++ components/esm/loadcell.cpp | 22 ++++++++++++++++++++-- 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bbc44f5e10..3e23679b13 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -190,8 +190,9 @@ namespace MWWorld // This parses the ESM file ESM::ESMReader lEsm; lEsm.setEncoding(encoding); - lEsm.open (masterPath.string()); lEsm.setIndex(idx); + lEsm.setGlobalReaderList(&mEsm); + lEsm.open (masterPath.string()); mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } @@ -205,8 +206,9 @@ namespace MWWorld // This parses the ESP file ESM::ESMReader lEsm; lEsm.setEncoding(encoding); - lEsm.open (pluginPath.string()); lEsm.setIndex(idx); + lEsm.setGlobalReaderList(&mEsm); + lEsm.open (pluginPath.string()); mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index d61564c676..335d123378 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -89,6 +89,7 @@ struct MasterData { std::string name; uint64_t size; + int index; // Position of the parent file in the global list of loaded files }; // Data that is only present in save game files diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 2915a1ce77..d1703a2ac2 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -1,5 +1,6 @@ #include "esmreader.hpp" #include +#include namespace ESM { @@ -61,6 +62,7 @@ void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) { openRaw(_esm, name); + std::string fname = boost::filesystem::path(name).filename().string(); if (getRecName() != "TES3") fail("Not a valid Morrowind file"); @@ -78,6 +80,29 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) MasterData m; m.name = getHString(); m.size = getHNLong("DATA"); + // Cache parent esX files by tracking their indices in the global list of + // all files/readers used by the engine. This will greaty help to accelerate + // parsing of reference IDs. + size_t index = ~0; + // TODO: check for case mismatch, it might be required on Windows. + size_t i = 0; + // FIXME: This is ugly! Make it nicer! + for (; i < idx; i++) { + const std::string &candidate = mGlobalReaderList->at(i).getContext().filename; + std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); + if (m.name == fnamecandidate) { + index = i; + break; + } + } + if (index == (size_t)~0) { + // Tried to load a parent file that has not been loaded yet. This is bad, + // the launcher should have taken care of this. + std::string fstring = "File " + fname + " asks for parent file " + m.name + + ", but it has not been loaded yet. Please check your load order."; + fail(fstring); + } + m.index = index; mMasters.push_back(m); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index f09442a577..b415009d34 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -83,6 +83,8 @@ public: int idx; void setIndex(const int index) {idx = index; mCtx.index = index;} const int getIndex() {return idx;} + + void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} /************************************************************************* * @@ -254,6 +256,7 @@ private: SaveData mSaveData; MasterList mMasters; + std::vector *mGlobalReaderList; ToUTF8::FromType mEncoding; }; } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index beedd3cacf..1a1811a90d 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -170,8 +170,6 @@ std::string Cell::getDescription() const bool Cell::getNextRef(ESMReader &esm, CellRef &ref) { - // TODO: Add support for multiple plugins. This requires a tricky renaming scheme for "ref.mRefnum". - // I'll probably add something to "ESMReader", we will need one per plugin anyway. // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; @@ -194,6 +192,26 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // This may require some not-so-small behing-the-scenes updates. esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); + + // Identify references belonging to a parent file and adapt the ID accordingly. + int local = (ref.mRefnum & 0xff000000) >> 24; + size_t global = esm.getIndex() + 1; + if (local) + { + // If the most significant 8 bits are used, then this reference already exists. + // In this case, do not spawn a new reference, but overwrite the old one. + ref.mRefnum &= 0x00ffffff; // delete old plugin ID + const ESM::ESMReader::MasterList &masters = esm.getMasters(); + // TODO: Test how Morrowind does it! Maybe the first entry in the list should be "1"... + global = masters[local-1].index + 1; + ref.mRefnum |= global << 24; // insert global plugin ID + std::cout << "Refnum_old = " << ref.mRefnum << " " << local << " " << global << std::endl; + } + else + { + // This is an addition by the present plugin. Set the corresponding plugin index. + ref.mRefnum |= global << 24; // insert global plugin ID + } // getHNOT will not change the existing value if the subrecord is // missing From 31fb715bd7be529689e66fb9a33fb5c51b105d3d Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 17 Nov 2012 21:50:25 +0100 Subject: [PATCH 0005/1483] - Add support for moving existing references by plugin files. No cell changing yet. - Change CellRefList::list from list<> to map so we can identify live references by their Refnumber. - Introduce ContainerRefList, a clone of the original CellRefList. It is now used for containers, which do not track Refnumbers. - Many small tweaks so that the new CellRefList does not conflict with existing code. --- apps/openmw/mwworld/cells.cpp | 12 ++--- apps/openmw/mwworld/cellstore.cpp | 6 +-- apps/openmw/mwworld/cellstore.hpp | 47 +++++++++++++++-- apps/openmw/mwworld/containerstore.cpp | 28 +++++----- apps/openmw/mwworld/containerstore.hpp | 72 +++++++++++++------------- apps/openmw/mwworld/localscripts.cpp | 4 +- apps/openmw/mwworld/scene.cpp | 6 +-- apps/openmw/mwworld/worldimp.cpp | 18 +++---- components/esm/loadcell.cpp | 6 +-- components/esm_store/reclists.hpp | 5 +- 10 files changed, 119 insertions(+), 85 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index e49835f412..667f2d4ca5 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -43,30 +43,30 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) cellStore.containers.list.begin()); iter!=cellStore.containers.list.end(); ++iter) { - Ptr container (&*iter, &cellStore); + Ptr container (&iter->second, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->second.base->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.creatures.list.begin()); iter!=cellStore.creatures.list.end(); ++iter) { - Ptr container (&*iter, &cellStore); + Ptr container (&iter->second, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->second.base->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.npcs.list.begin()); iter!=cellStore.npcs.list.end(); ++iter) { - Ptr container (&*iter, &cellStore); + Ptr container (&iter->second, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->second.base->mInventory, mStore); } } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 91c0afe26f..0af8861243 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -65,8 +65,7 @@ namespace MWWorld std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: Fully support deletion / moving references out of the cell. no simple "push_back", - // but make sure that the reference exists only once. + // TODO: Fully support deletion of references. mIds.push_back (lowerCase); } } @@ -98,8 +97,7 @@ namespace MWWorld std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: Fully support deletion / moving references out of the cell. No simple loading, - // but make sure that the reference exists only once. Current code clones references. + // TODO: Fully support deletion of references. int rec = store.find(ref.mRefID); ref.mRefID = lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 69c4cf9b4b..236f672311 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -47,6 +47,47 @@ namespace MWWorld /// A list of cell references template struct CellRefList + { + typedef LiveCellRef LiveRef; + typedef std::map List; + List list; + + // Search for the given reference in the given reclist from + // ESMStore. Insert the reference into the list if a match is + // found. If not, throw an exception. + template + void find(ESM::CellRef &ref, const Y& recList) + { + const X* obj = recList.find(ref.mRefID); + if(obj == NULL) + throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + + list[ref.mRefnum] = LiveRef(ref, obj); + } + + LiveRef *find (const std::string& name) + { + for (typename std::map::iterator iter (list.begin()); iter!=list.end(); ++iter) + { + if (iter->second.mData.getCount() > 0 && iter->second.ref.mRefID == name) + return &iter->second; + } + + return 0; + } + + LiveRef &insert(const LiveRef &item) { + list[item.ref.mRefnum] = item; + return list[item.ref.mRefnum]; + } + }; + + /// A list of container references. These references do not track their mRefnumber. + /// Otherwise, taking 1 of 20 instances of an object would produce multiple objects + /// with the same reference. + // TODO: Check how Morrowind does this! Maybe auto-generate references on drop. + template + struct ContainerRefList { typedef LiveCellRef LiveRef; typedef std::list List; @@ -62,10 +103,6 @@ namespace MWWorld if(obj == NULL) throw std::runtime_error("Error resolving cell reference " + ref.mRefID); - // TODO: this line must be modified for multiple plugins and moved references. - // This means: no simple "push back", but search for an existing reference with - // this ID first! If it exists, merge data into this list instead of just adding it. - // I'll probably generate a separate method jist for this. list.push_back(LiveRef(ref, obj)); } @@ -180,7 +217,7 @@ namespace MWWorld { for (typename List::List::iterator iter (list.list.begin()); iter!=list.list.end(); ++iter) - if (!functor (iter->ref, iter->mData)) + if (!functor (iter->second.ref, iter->second.mData)) return false; return true; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5c4dd03a45..035f79310f 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -19,11 +19,11 @@ namespace { template - float getTotalWeight (const MWWorld::CellRefList& cellRefList) + float getTotalWeight (const MWWorld::ContainerRefList& cellRefList) { float sum = 0; - for (typename MWWorld::CellRefList::List::const_iterator iter ( + for (typename MWWorld::ContainerRefList::List::const_iterator iter ( cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) @@ -270,29 +270,29 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor ++*this; } -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Potion), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mPotion(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Apparatus), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mApparatus(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Armor), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mArmor(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Book), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mBook(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Clothing), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mClothing(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Probe), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mProbe(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Repair), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mRepair(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Weapon), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mWeapon(iterator){} void MWWorld::ContainerStoreIterator::incType() diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index ae27fad3d3..9611b9c219 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -37,18 +37,18 @@ namespace MWWorld private: - MWWorld::CellRefList potions; - MWWorld::CellRefList appas; - MWWorld::CellRefList armors; - MWWorld::CellRefList books; - MWWorld::CellRefList clothes; - MWWorld::CellRefList ingreds; - MWWorld::CellRefList lights; - MWWorld::CellRefList lockpicks; - MWWorld::CellRefList miscItems; - MWWorld::CellRefList probes; - MWWorld::CellRefList repairs; - MWWorld::CellRefList weapons; + MWWorld::ContainerRefList potions; + MWWorld::ContainerRefList appas; + MWWorld::ContainerRefList armors; + MWWorld::ContainerRefList books; + MWWorld::ContainerRefList clothes; + MWWorld::ContainerRefList ingreds; + MWWorld::ContainerRefList lights; + MWWorld::ContainerRefList lockpicks; + MWWorld::ContainerRefList miscItems; + MWWorld::ContainerRefList probes; + MWWorld::ContainerRefList repairs; + MWWorld::ContainerRefList weapons; int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; @@ -119,18 +119,18 @@ namespace MWWorld ContainerStore *mContainer; mutable Ptr mPtr; - MWWorld::CellRefList::List::iterator mPotion; - MWWorld::CellRefList::List::iterator mApparatus; - MWWorld::CellRefList::List::iterator mArmor; - MWWorld::CellRefList::List::iterator mBook; - MWWorld::CellRefList::List::iterator mClothing; - MWWorld::CellRefList::List::iterator mIngredient; - MWWorld::CellRefList::List::iterator mLight; - MWWorld::CellRefList::List::iterator mLockpick; - MWWorld::CellRefList::List::iterator mMiscellaneous; - MWWorld::CellRefList::List::iterator mProbe; - MWWorld::CellRefList::List::iterator mRepair; - MWWorld::CellRefList::List::iterator mWeapon; + MWWorld::ContainerRefList::List::iterator mPotion; + MWWorld::ContainerRefList::List::iterator mApparatus; + MWWorld::ContainerRefList::List::iterator mArmor; + MWWorld::ContainerRefList::List::iterator mBook; + MWWorld::ContainerRefList::List::iterator mClothing; + MWWorld::ContainerRefList::List::iterator mIngredient; + MWWorld::ContainerRefList::List::iterator mLight; + MWWorld::ContainerRefList::List::iterator mLockpick; + MWWorld::ContainerRefList::List::iterator mMiscellaneous; + MWWorld::ContainerRefList::List::iterator mProbe; + MWWorld::ContainerRefList::List::iterator mRepair; + MWWorld::ContainerRefList::List::iterator mWeapon; private: @@ -141,18 +141,18 @@ namespace MWWorld ///< Begin-iterator // construct iterator using a CellRefList iterator - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); void incType(); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index d0d698feb6..1ef1cdeaf1 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -15,9 +15,9 @@ namespace cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) { - if (!iter->base->mScript.empty() && iter->mData.getCount()) + if (!iter->second.base->mScript.empty() && iter->second.mData.getCount()) { - localScripts.add (iter->base->mScript, MWWorld::Ptr (&*iter, cell)); + localScripts.add (iter->second.base->mScript, MWWorld::Ptr (&iter->second, cell)); } } } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 881b090fa5..b6add7fbfc 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -23,7 +23,7 @@ namespace if (!cellRefList.list.empty()) { const MWWorld::Class& class_ = - MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.list.begin(), &cell)); + MWWorld::Class::get (MWWorld::Ptr (&cellRefList.list.begin()->second, &cell)); int numRefs = cellRefList.list.size(); int current = 0; @@ -33,9 +33,9 @@ namespace MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; - if (it->mData.getCount() || it->mData.isEnabled()) + if (it->second.mData.getCount() || it->second.mData.isEnabled()) { - MWWorld::Ptr ptr (&*it, &cell); + MWWorld::Ptr ptr (&it->second, &cell); try { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3e23679b13..e999100f0e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -28,13 +28,13 @@ namespace cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) { - if (!iter->base->script.empty() && iter->mData.getCount()) + if (!iter->second->base->script.empty() && iter->second->mData.getCount()) { - if (const ESM::Script *script = store.scripts.find (iter->base->script)) + if (const ESM::Script *script = store.scripts.find (iter->second->base->script)) { iter->mData.setLocals (*script); - localScripts.add (iter->base->script, MWWorld::Ptr (&*iter, cell)); + localScripts.add (iter->base->script, MWWorld::Ptr (&iter->second, cell)); } } } @@ -48,10 +48,10 @@ namespace for (iterator iter (refList.list.begin()); iter!=refList.list.end(); ++iter) { - if(iter->mData.getCount() > 0 && iter->mData.getBaseNode()){ - if (iter->mData.getHandle()==handle) + if (iter->second.mData.getCount() > 0 && iter->second.mData.getBaseNode()){ + if (iter->second.mData.getHandle()==handle) { - return &*iter; + return &iter->second; } } } @@ -1115,10 +1115,10 @@ namespace MWWorld std::vector result; MWWorld::CellRefList& doors = cell->doors; - std::list< MWWorld::LiveCellRef >& refList = doors.list; - for (std::list< MWWorld::LiveCellRef >::iterator it = refList.begin(); it != refList.end(); ++it) + std::map >& refList = doors.list; + for (std::map >::iterator it = refList.begin(); it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + MWWorld::LiveCellRef& ref = it->second; if (ref.ref.mTeleport) { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 1a1811a90d..b7f27b08d0 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -113,8 +113,6 @@ void Cell::load(ESMReader &esm) // Save position of the cell references and move on mContextList.push_back(esm.getContext()); - if (mContextList.size() > 1) - std::cout << "found two plugins" << std::endl; esm.skipRecord(); } @@ -202,10 +200,8 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // In this case, do not spawn a new reference, but overwrite the old one. ref.mRefnum &= 0x00ffffff; // delete old plugin ID const ESM::ESMReader::MasterList &masters = esm.getMasters(); - // TODO: Test how Morrowind does it! Maybe the first entry in the list should be "1"... global = masters[local-1].index + 1; ref.mRefnum |= global << 24; // insert global plugin ID - std::cout << "Refnum_old = " << ref.mRefnum << " " << local << " " << global << std::endl; } else { @@ -256,7 +252,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNOT(ref.mFltv, "FLTV"); esm.getHNT(ref.mPos, "DATA", 24); - + // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 44b7e6569e..14452fca92 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -523,7 +523,10 @@ namespace ESMS // Store exterior cells by grid position, try to merge with existing parent data. ESM::Cell *oldcell = const_cast(searchExt(cell->getGridX(), cell->getGridY())); if (oldcell) { - cell->mContextList.push_back(oldcell->mContextList.at(0)); + // The load order is important. Push the new source context on the *back* of the existing list, + // and then move the list to the new cell. + oldcell->mContextList.push_back(cell->mContextList.at(0)); + cell->mContextList = oldcell->mContextList; delete oldcell; } extCells[std::make_pair (cell->mData.mX, cell->mData.mY)] = cell; From 896ab44d1e919852aae03be9ecb71378f031b6f5 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 25 Nov 2012 17:19:29 +0100 Subject: [PATCH 0006/1483] - Add some updated files missing from last commit. - Move plugin dependency test from esmreader.cpp to esmstpre.cpp; fixes crash in omwlauncher. --- apps/openmw/CMakeLists.txt | 7 ++-- apps/openmw/mwrender/terrain.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 8 ++-- apps/openmw/mwworld/cellstore.hpp | 28 ++++++++------ apps/openmw/mwworld/esmstore.cpp | 29 ++++++++++++++ apps/openmw/mwworld/store.hpp | 64 +++++++++++++++++++++---------- apps/openmw/mwworld/worldimp.cpp | 4 +- components/esm/esmreader.cpp | 25 ------------ components/esm/esmreader.hpp | 1 + 9 files changed, 102 insertions(+), 66 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 538f63dc96..e2a2e7f145 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -34,7 +34,7 @@ add_openmw_dir (mwgui ) add_openmw_dir (mwdialogue - dialoguemanagerimp journalimp journalentry quest topic + dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper ) add_openmw_dir (mwscript @@ -50,9 +50,10 @@ add_openmw_dir (mwsound add_openmw_dir (mwworld refdata worldimp physicssystem scene globals class action nullaction actionteleport - containerstore actiontalk actiontake manualref player cellfunctors + containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat + esmstore store recordcmp ) add_openmw_dir (mwclass @@ -62,7 +63,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells - activespells npcstats aipackage aisequence alchemy + activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index d46c2521f0..eb5b07af40 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -221,7 +221,7 @@ 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); + int num = MWBase::Environment::get().getWorld()->getStore().get().getSize(plugin); std::set ltexIndexes; for ( int y = fromY - 1; y < fromY + size + 1; y++ ) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 74856c9ed9..ba8f5aa613 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -49,10 +49,10 @@ namespace MWWorld return; // this is a dynamically generated cell -> skipping. // Load references from all plugins that do something with this cell. - for (size_t i = 0; i < cell->mContextList.size(); i++) + for (size_t i = 0; i < mCell->mContextList.size(); i++) { // Reopen the ESM reader and seek to the right position. - int index = cell->mContextList.at(i).index; + int index = mCell->mContextList.at(i).index; mCell->restore (esm[index], i); ESM::CellRef ref; @@ -81,10 +81,10 @@ namespace MWWorld return; // this is a dynamically generated cell -> skipping. // Load references from all plugins that do something with this cell. - for (size_t i = 0; i < cell->mContextList.size(); i++) + for (size_t i = 0; i < mCell->mContextList.size(); i++) { // Reopen the ESM reader and seek to the right position. - int index = cell->mContextList.at(i).index; + int index = mCell->mContextList.at(i).index; mCell->restore (esm[index], i); ESM::CellRef ref; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index b66137cc6b..bf7581f6ed 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -49,26 +49,32 @@ namespace MWWorld { typedef LiveCellRef LiveRef; typedef std::map List; - List list; + List mList; // Search for the given reference in the given reclist from // ESMStore. Insert the reference into the list if a match is // found. If not, throw an exception. - template - void find(ESM::CellRef &ref, const Y& recList) + /// Searches for reference of appropriate type in given ESMStore. + /// If reference exists, loads it into container, throws an exception + /// on miss + void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) { - const X* obj = recList.find(ref.mRefID); - if(obj == NULL) - throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + // for throwing exception on unhandled record type + const MWWorld::Store &store = esmStore.get(); + const X *ptr = store.find(ref.mRefID); - list[ref.mRefnum] = LiveRef(ref, obj); + /// \note redundant because Store::find() throws exception on miss + if (ptr == NULL) { + throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + } + mList[ref.mRefnum] = LiveRef(ref, ptr); } LiveRef *find (const std::string& name) { - for (typename std::map::iterator iter (list.begin()); iter!=list.end(); ++iter) + for (typename std::map::iterator iter (mList.begin()); iter!=mList.end(); ++iter) { - if (iter->second.mData.getCount() > 0 && iter->second.ref.mRefID == name) + if (iter->second.mData.getCount() > 0 && iter->second.mRef.mRefID == name) return &iter->second; } @@ -76,8 +82,8 @@ namespace MWWorld } LiveRef &insert(const LiveRef &item) { - list[item.ref.mRefnum] = item; - return list[item.ref.mRefnum]; + mList[item.mRef.mRefnum] = item; + return mList[item.mRef.mRefnum]; } }; diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 73f5185c98..db444153fc 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -3,6 +3,8 @@ #include #include +#include + namespace MWWorld { @@ -25,6 +27,33 @@ void ESMStore::load(ESM::ESMReader &esm) ESM::Dialogue *dialogue = 0; + // Cache parent esX files by tracking their indices in the global list of + // all files/readers used by the engine. This will greaty help to accelerate + // parsing of reference IDs. + size_t index = ~0; + const ESM::ESMReader::MasterList &masters = esm.getMasters(); + std::vector *allPlugins = esm.getGlobalReaderList(); + for (size_t j = 0; j < masters.size(); j++) { + ESM::MasterData &mast = const_cast(masters[j]); + std::string fname = mast.name; + for (size_t i = 0; i < esm.getIndex(); i++) { + const std::string &candidate = allPlugins->at(i).getContext().filename; + std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); + if (fname == fnamecandidate) { + index = i; + break; + } + } + if (index == (size_t)~0) { + // Tried to load a parent file that has not been loaded yet. This is bad, + // the launcher should have taken care of this. + std::string fstring = "File " + fname + " asks for parent file " + masters[j].name + + ", but it has not been loaded yet. Please check your load order."; + esm.fail(fstring); + } + mast.index = index; + } + // Loop through all records while(esm.hasMoreRecs()) { diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fd93f39f1e..53f4482bb3 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -219,24 +219,31 @@ namespace MWWorld template <> class Store : public StoreBase { - std::vector mStatic; + // For multiple ESM/ESP files we need one list per file. + typedef std::vector LandTextureList; + std::vector mStatic; public: Store() { - mStatic.reserve(128); + mStatic.push_back(LandTextureList()); + LandTextureList <exl = mStatic[0]; + // More than enough to hold Morrowind.esm. Extra lists for plugins will we + // added on-the-fly in a different method. + ltexl.reserve(128); } typedef std::vector::const_iterator iterator; - const ESM::LandTexture *search(size_t index) const { - if (index < mStatic.size()) { - return &mStatic.at(index); - } - return 0; + const ESM::LandTexture *search(size_t index, size_t plugin) const { + assert(plugin < mStatic.size()); + const LandTextureList <exl = mStatic[plugin]; + + assert(index < ltexl.size()); + return <exl.at(index); } - const ESM::LandTexture *find(size_t index) const { - const ESM::LandTexture *ptr = search(index); + const ESM::LandTexture *find(size_t index, size_t plugin) const { + const ESM::LandTexture *ptr = search(index, plugin); if (ptr == 0) { std::ostringstream msg; msg << "Land texture with index " << index << " not found"; @@ -249,23 +256,40 @@ namespace MWWorld return mStatic.size(); } - void load(ESM::ESMReader &esm, const std::string &id) { - ESM::LandTexture ltex; - ltex.load(esm); + int getSize(size_t plugin) const { + assert(plugin < mStatic.size()); + return mStatic[plugin].size(); + } - if (ltex.mIndex >= (int) mStatic.size()) { - mStatic.resize(ltex.mIndex + 1); + void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) { + ESM::LandTexture lt; + lt.load(esm); + lt.mId = id; + + // Make sure we have room for the structure + if (plugin >= mStatic.size()) { + mStatic.resize(plugin+1); } - mStatic[ltex.mIndex] = ltex; - mStatic[ltex.mIndex].mId = id; + LandTextureList <exl = mStatic[plugin]; + if(lt.mIndex + 1 > (int)ltexl.size()) + ltexl.resize(lt.mIndex+1); + + // Store it + ltexl[lt.mIndex] = lt; } - iterator begin() const { - return mStatic.begin(); + void load(ESM::ESMReader &esm, const std::string &id) { + load(esm, id, esm.getIndex()); } - iterator end() const { - return mStatic.end(); + iterator begin(size_t plugin) const { + assert(plugin < mStatic.size()); + return mStatic[plugin].begin(); + } + + iterator end(size_t plugin) const { + assert(plugin < mStatic.size()); + return mStatic[plugin].end(); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9f2d419f16..1fa23700d7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1081,8 +1081,8 @@ namespace MWWorld std::vector result; MWWorld::CellRefList& doors = cell->mDoors; - std::map< MWWorld::LiveCellRef >& refList = doors.mList; - for (std::map >::iterator it = refList.begin(); it != refList.end(); ++it) + CellRefList::List& refList = doors.mList; + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = it->second; diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index d1703a2ac2..2915a1ce77 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -1,6 +1,5 @@ #include "esmreader.hpp" #include -#include namespace ESM { @@ -62,7 +61,6 @@ void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) { openRaw(_esm, name); - std::string fname = boost::filesystem::path(name).filename().string(); if (getRecName() != "TES3") fail("Not a valid Morrowind file"); @@ -80,29 +78,6 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) MasterData m; m.name = getHString(); m.size = getHNLong("DATA"); - // Cache parent esX files by tracking their indices in the global list of - // all files/readers used by the engine. This will greaty help to accelerate - // parsing of reference IDs. - size_t index = ~0; - // TODO: check for case mismatch, it might be required on Windows. - size_t i = 0; - // FIXME: This is ugly! Make it nicer! - for (; i < idx; i++) { - const std::string &candidate = mGlobalReaderList->at(i).getContext().filename; - std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); - if (m.name == fnamecandidate) { - index = i; - break; - } - } - if (index == (size_t)~0) { - // Tried to load a parent file that has not been loaded yet. This is bad, - // the launcher should have taken care of this. - std::string fstring = "File " + fname + " asks for parent file " + m.name - + ", but it has not been loaded yet. Please check your load order."; - fail(fstring); - } - m.index = index; mMasters.push_back(m); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index b415009d34..732dbe9bc6 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -85,6 +85,7 @@ public: const int getIndex() {return idx;} void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} + std::vector *getGlobalReaderList() {return mGlobalReaderList;} /************************************************************************* * From b103426cf0f1a45efa97ca4d3cf215ee8640dc4f Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 25 Nov 2012 19:07:16 +0100 Subject: [PATCH 0007/1483] - Partially reimplement deleting objects defined in a parent esX file. - Try to reimplement multiple esX files dropping references in the same file. NOTE: None of these features works. Maybe the code itself does not build. Anyway, after 12 hours of hacking, I am just tired and want to get a snapshot of the code out. --- apps/openmw/mwworld/cellstore.cpp | 2 ++ apps/openmw/mwworld/esmstore.cpp | 11 ++++++- apps/openmw/mwworld/esmstore.hpp | 3 +- apps/openmw/mwworld/store.hpp | 48 ++++++++++++++++++++++++++----- apps/openmw/mwworld/worldimp.cpp | 2 ++ components/esm/loadcell.cpp | 1 + 6 files changed, 58 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ba8f5aa613..ff8368dd16 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -83,6 +83,8 @@ namespace MWWorld // Load references from all plugins that do something with this cell. for (size_t i = 0; i < mCell->mContextList.size(); i++) { + if (mCell->mContextList.size() > 1) + std::cout << "number of lists " << mCell->mContextList.size() << std::endl; // Reopen the ESM reader and seek to the right position. int index = mCell->mContextList.at(i).index; mCell->restore (esm[index], i); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index db444153fc..5641267978 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -84,6 +84,15 @@ void ESMStore::load(ESM::ESMReader &esm) } else { // Load it std::string id = esm.getHNOString("NAME"); + // ... unless it got deleted! This means that the following record + // has been deleted, and trying to load it using standard assumptions + // on the structure will (probably) fail. + 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) { @@ -113,7 +122,7 @@ void ESMStore::load(ESM::ESMReader &esm) cout << *it << " "; cout << endl; */ - setUp(); + //setUp(); } void ESMStore::setUp() diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 9917254ee7..bd8e003f4a 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -168,7 +168,8 @@ namespace MWWorld return ptr; } - private: + // This method must be called once, after loading all master/plugin files. This can only be done + // from the outside, so it must be public. void setUp(); }; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 53f4482bb3..d4d632eff0 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -473,14 +473,48 @@ namespace MWWorld } void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Cell cell; - cell.mName = id; - cell.load(esm); + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded! So first, proceed as usual. + + // All cells have a name record, even nameless exterior cells. + ESM::Cell *cell = new ESM::Cell; + cell->mName = id; - if (cell.isExterior()) { - mExt.push_back(cell); - } else { - mInt.push_back(cell); + // The cell itself takes care of all the hairy details + cell->load(esm); + + if(cell->mData.mFlags & ESM::Cell::Interior) + { + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(id)); + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // have new cell replace old cell + *oldcell = *cell; + } else + mInt.push_back(*cell); + delete cell; + } + else + { + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); + std::cout << "setup - " << oldcell << " " << cell->getGridX() << " " << cell->getGridY() << std::endl; + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // have new cell replace old cell + *oldcell = *cell; + } else + mExt.push_back(*cell); + delete cell; } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1fa23700d7..6dbba2a456 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -215,6 +215,8 @@ namespace MWWorld mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } + + mStore.setUp(); mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); mRendering->attachCameraTo(mPlayer->getPlayer()); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index b7f27b08d0..0158af70a9 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -201,6 +201,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mRefnum &= 0x00ffffff; // delete old plugin ID const ESM::ESMReader::MasterList &masters = esm.getMasters(); global = masters[local-1].index + 1; + std::cout << "moved ref: " << local << " " << global << std::endl; ref.mRefnum |= global << 24; // insert global plugin ID } else From 049b0e66e0e63e5ac9c9ebdb837c371964ae856b Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Tue, 25 Dec 2012 20:27:30 +0100 Subject: [PATCH 0008/1483] - Restore ability to generate references in the same cell from multiple plugins - Disable some code related to deleting entries in the store so that it builds again --- apps/openmw/mwworld/cellstore.cpp | 2 -- apps/openmw/mwworld/esmstore.cpp | 2 ++ apps/openmw/mwworld/store.hpp | 48 +++++++++++++++---------------- components/esm/loadcell.cpp | 1 - 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ff8368dd16..ba8f5aa613 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -83,8 +83,6 @@ namespace MWWorld // Load references from all plugins that do something with this cell. for (size_t i = 0; i < mCell->mContextList.size(); i++) { - if (mCell->mContextList.size() > 1) - std::cout << "number of lists " << mCell->mContextList.size() << std::endl; // Reopen the ESM reader and seek to the right position. int index = mCell->mContextList.at(i).index; mCell->restore (esm[index], i); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 5641267978..b1b9b15347 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -87,12 +87,14 @@ void ESMStore::load(ESM::ESMReader &esm) // ... unless it got deleted! This means that the following record // has been deleted, and trying to load it using standard assumptions // on the structure will (probably) fail. + /* 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) { diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index d4d632eff0..fd3e9c59c8 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -371,15 +371,15 @@ namespace MWWorld } }; - std::vector mInt; - std::vector mExt; + typedef std::map DynamicInt; + typedef std::map, ESM::Cell> DynamicExt; + + DynamicInt mInt; + DynamicExt mExt; std::vector mSharedInt; std::vector mSharedExt; - typedef std::map DynamicInt; - typedef std::map, ESM::Cell> DynamicExt; - DynamicInt mDynamicInt; DynamicExt mDynamicExt; @@ -401,11 +401,10 @@ namespace MWWorld ESM::Cell cell; cell.mName = StringUtils::lowerCase(id); - std::vector::const_iterator it = - std::lower_bound(mInt.begin(), mInt.end(), cell, RecordCmp()); + std::map::const_iterator it = mInt.find(cell.mName); - if (it != mInt.end() && StringUtils::ciEqual(it->mName, id)) { - return &(*it); + if (it != mInt.end() && StringUtils::ciEqual(it->second.mName, id)) { + return &(it->second); } DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); @@ -420,14 +419,12 @@ namespace MWWorld ESM::Cell cell; cell.mData.mX = x, cell.mData.mY = y; - std::vector::const_iterator it = - std::lower_bound(mExt.begin(), mExt.end(), cell, ExtCmp()); - - if (it != mExt.end() && it->mData.mX == x && it->mData.mY == y) { - return &(*it); + std::pair key(x, y); + std::map, ESM::Cell>::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); } - std::pair key(x, y); DynamicExt::const_iterator dit = mDynamicExt.find(key); if (dit != mDynamicExt.end()) { return &dit->second; @@ -457,18 +454,20 @@ namespace MWWorld } void setUp() { - typedef std::vector::iterator Iterator; + //typedef std::vector::iterator Iterator; + typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef std::map::iterator IntIterator; - std::sort(mInt.begin(), mInt.end(), RecordCmp()); + //std::sort(mInt.begin(), mInt.end(), RecordCmp()); mSharedInt.reserve(mInt.size()); - for (Iterator it = mInt.begin(); it != mInt.end(); ++it) { - mSharedInt.push_back(&(*it)); + for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { + mSharedInt.push_back(&(it->second)); } - std::sort(mExt.begin(), mExt.end(), ExtCmp()); + //std::sort(mExt.begin(), mExt.end(), ExtCmp()); mSharedExt.reserve(mExt.size()); - for (Iterator it = mExt.begin(); it != mExt.end(); ++it) { - mSharedExt.push_back(&(*it)); + for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { + mSharedExt.push_back(&(it->second)); } } @@ -497,14 +496,13 @@ namespace MWWorld // have new cell replace old cell *oldcell = *cell; } else - mInt.push_back(*cell); + mInt[cell->mName] = *cell; delete cell; } else { // Store exterior cells by grid position, try to merge with existing parent data. ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); - std::cout << "setup - " << oldcell << " " << cell->getGridX() << " " << cell->getGridY() << std::endl; if (oldcell) { // push the new references on the list of references to manage oldcell->mContextList.push_back(cell->mContextList.at(0)); @@ -513,7 +511,7 @@ namespace MWWorld // have new cell replace old cell *oldcell = *cell; } else - mExt.push_back(*cell); + mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; delete cell; } } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 0158af70a9..b7f27b08d0 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -201,7 +201,6 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mRefnum &= 0x00ffffff; // delete old plugin ID const ESM::ESMReader::MasterList &masters = esm.getMasters(); global = masters[local-1].index + 1; - std::cout << "moved ref: " << local << " " << global << std::endl; ref.mRefnum |= global << 24; // insert global plugin ID } else From 8ccec174811ccb3a58d1289531a0e29783f99602 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Wed, 26 Dec 2012 10:34:59 +0100 Subject: [PATCH 0009/1483] - Restore ability for plugins deleting records defined in parent files - Don't throw a runtime_error when trying to load a reference based on a deleted record (just a warning for now, should be closer to MW) --- apps/openmw/mwworld/cellstore.hpp | 11 +++--- apps/openmw/mwworld/esmstore.cpp | 15 ++++---- apps/openmw/mwworld/store.hpp | 58 ++++++++++++++++++++----------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index bf7581f6ed..cf09496e87 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -61,13 +61,14 @@ namespace MWWorld { // for throwing exception on unhandled record type const MWWorld::Store &store = esmStore.get(); - const X *ptr = store.find(ref.mRefID); + const X *ptr = store.search(ref.mRefID); - /// \note redundant because Store::find() throws exception on miss + /// \note no longer redundant - changed to Store::search(), don't throw + /// an exception on miss, try to continue (that's how MW does it, anyway) if (ptr == NULL) { - throw std::runtime_error("Error resolving cell reference " + ref.mRefID); - } - mList[ref.mRefnum] = LiveRef(ref, ptr); + std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl; + } else + mList[ref.mRefnum] = LiveRef(ref, ptr); } LiveRef *find (const std::string& name) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index b1b9b15347..54050b38c7 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -87,20 +87,18 @@ void ESMStore::load(ESM::ESMReader &esm) // ... unless it got deleted! This means that the following record // has been deleted, and trying to load it using standard assumptions // on the structure will (probably) fail. - /* if (esm.isNextSub("DELE")) { esm.skipRecord(); - all.erase(id); - it->second->remove(id); + it->second->eraseStatic(id); continue; } - */ it->second->load(esm, id); if (n.val==ESM::REC_DIAL) { // dirty hack, but it is better than non-const search() // or friends - dialogue = &mDialogs.mStatic.back(); + //dialogue = &mDialogs.mStatic.back(); + dialogue = const_cast(mDialogs.find(id)); assert (dialogue->mId == id); } else { dialogue = 0; @@ -140,12 +138,11 @@ void ESMStore::setUp() ESM::NPC item; item.mId = "player"; - std::vector::iterator pIt = - std::lower_bound(mNpcs.mStatic.begin(), mNpcs.mStatic.end(), item, RecordCmp()); - assert(pIt != mNpcs.mStatic.end() && pIt->mId == "player"); + const ESM::NPC *pIt = mNpcs.find("player"); + assert(pIt != NULL); mNpcs.insert(*pIt); - mNpcs.mStatic.erase(pIt); + mNpcs.eraseStatic(pIt->mId); } } // end namespace diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fd3e9c59c8..77c9c73574 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -19,6 +19,8 @@ namespace MWWorld virtual int getSize() const = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; + + virtual bool eraseStatic(const std::string &id) {return false;} }; template @@ -85,7 +87,7 @@ namespace MWWorld template class Store : public StoreBase { - std::vector mStatic; + std::map mStatic; std::vector mShared; std::map mDynamic; @@ -107,11 +109,10 @@ namespace MWWorld T item; item.mId = StringUtils::lowerCase(id); - typename std::vector::const_iterator it = - std::lower_bound(mStatic.begin(), mStatic.end(), item, RecordCmp()); - - if (it != mStatic.end() && StringUtils::ciEqual(it->mId, id)) { - return &(*it); + typename std::map::const_iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && StringUtils::ciEqual(it->second.mId, id)) { + return &(it->second); } typename Dynamic::const_iterator dit = mDynamic.find(item.mId); @@ -133,18 +134,19 @@ namespace MWWorld } void load(ESM::ESMReader &esm, const std::string &id) { - mStatic.push_back(T()); - mStatic.back().mId = StringUtils::lowerCase(id); - mStatic.back().load(esm); + std::string idLower = StringUtils::lowerCase(id); + mStatic[idLower] = T(); + mStatic[idLower].mId = idLower; + mStatic[idLower].load(esm); } void setUp() { - std::sort(mStatic.begin(), mStatic.end(), RecordCmp()); + //std::sort(mStatic.begin(), mStatic.end(), RecordCmp()); mShared.reserve(mStatic.size()); - typename std::vector::iterator it = mStatic.begin(); + typename std::map::iterator it = mStatic.begin(); for (; it != mStatic.end(); ++it) { - mShared.push_back(&(*it)); + mShared.push_back(&(it->second)); } } @@ -181,6 +183,19 @@ namespace MWWorld return ptr; } + bool eraseStatic(const std::string &id) { + T item; + item.mId = StringUtils::lowerCase(id); + + typename std::map::const_iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && StringUtils::ciEqual(it->second.mId, id)) { + mStatic.erase(it); + } + + return true; + } + bool erase(const std::string &id) { std::string key = StringUtils::lowerCase(id); typename Dynamic::iterator it = mDynamic.find(key); @@ -204,16 +219,18 @@ namespace MWWorld template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - mStatic.push_back(ESM::Dialogue()); - mStatic.back().mId = id; - mStatic.back().load(esm); + std::string idLower = StringUtils::lowerCase(id); + mStatic[idLower] = ESM::Dialogue(); + mStatic[idLower].mId = id; // don't smash case here, as this line is printed... I think + mStatic[idLower].load(esm); } template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - mStatic.push_back(ESM::Script()); - mStatic.back().load(esm); - StringUtils::toLower(mStatic.back().mId); + ESM::Script scpt; + scpt.load(esm); + StringUtils::toLower(scpt.mId); + mStatic[scpt.mId] = scpt; } template <> @@ -478,6 +495,7 @@ namespace MWWorld // are not available until both cells have been loaded! So first, proceed as usual. // All cells have a name record, even nameless exterior cells. + std::string idLower = StringUtils::lowerCase(id); ESM::Cell *cell = new ESM::Cell; cell->mName = id; @@ -487,7 +505,7 @@ namespace MWWorld if(cell->mData.mFlags & ESM::Cell::Interior) { // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(id)); + ESM::Cell *oldcell = const_cast(search(idLower)); if (oldcell) { // push the new references on the list of references to manage oldcell->mContextList.push_back(cell->mContextList.at(0)); @@ -496,7 +514,7 @@ namespace MWWorld // have new cell replace old cell *oldcell = *cell; } else - mInt[cell->mName] = *cell; + mInt[idLower] = *cell; delete cell; } else From 2cef65a056d7d67ba5f6607efefeeb18bef43e24 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Thu, 27 Dec 2012 20:11:58 +0100 Subject: [PATCH 0010/1483] - Remove some files that are no longer in upstream/master --- components/esm_store/reclists.hpp | 735 ------------------------------ components/esm_store/store.cpp | 124 ----- 2 files changed, 859 deletions(-) delete mode 100644 components/esm_store/reclists.hpp delete mode 100644 components/esm_store/store.cpp diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp deleted file mode 100644 index 14452fca92..0000000000 --- a/components/esm_store/reclists.hpp +++ /dev/null @@ -1,735 +0,0 @@ -#ifndef _GAME_ESM_RECLISTS_H -#define _GAME_ESM_RECLISTS_H - -#include "components/esm/records.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -using namespace boost::algorithm; - -namespace ESMS -{ - using namespace ESM; - - struct RecList - { - virtual ~RecList() {} - - 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) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } - }; - - typedef std::map RecListList; - - template - struct RecListT : RecList - { - virtual ~RecListT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = toLower (id); - list[id2].load(esm); - } - - // Delete the given object ID. Plugin files support this, so we need to do this, too. - 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 - { - std::string id2 = toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - // Same as RecListT, but does not case-smash the IDs - // Note that lookups (search or find) are still case insensitive - template - struct RecListCaseT : RecList - { - virtual ~RecListCaseT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - //std::string id2 = toLower (id); - - list[id].load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - for (typename MapType::const_iterator iter = list.begin(); - iter != list.end(); ++iter) - { - if (toLower(iter->first) == id2) - return &iter->second; - } - - return NULL; - } - - // non-const version - X* search(const std::string &id) - { - std::string id2 = toLower (id); - - for (typename MapType::iterator iter = list.begin(); - iter != list.end(); ++iter) - { - if (toLower(iter->first) == id2) - return &iter->second; - } - - return NULL; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - /// Modified version of RecListT for records, that need to store their own ID - template - struct RecListWithIDT : RecList - { - virtual ~RecListWithIDT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = toLower (id); - list[id2].mId = id2; - list[id2].load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - // The only difference to the above is a slight change to the load() - // function. We might merge these together later, and store the id - // in all the structs. - template - struct RecIDListT : RecList - { - virtual ~RecIDListT() {} - - typedef std::map MapType; - - MapType list; - - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = toLower (id); - X& ref = list[id2]; - - ref.mId = id; - ref.load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - /* Land textures are indexed by an integer number - */ - struct LTexList : RecList - { - virtual ~LTexList() {} - - // 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. Extra lists for plugins will we - // added on-the-fly in a different method. - ltexl.reserve(128); - } - - const LandTexture* search(size_t index, size_t plugin) const - { - assert(plugin < ltex.size()); - const LandTextureList <exl = ltex[plugin]; - - assert(index < ltexl.size()); - return <exl.at(index); - } - - // "getSize" returns the number of individual terrain palettes. - // "getSizePlugin" returns the number of land textures in a specific palette. - 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 {} - - void load(ESMReader &esm, const std::string &id, size_t plugin) - { - LandTexture lt; - lt.load(esm); - lt.mId = id; - - // Make sure we have room for the structure - if (plugin >= ltex.size()) { - ltex.resize(plugin+1); - } - LandTextureList <exl = ltex[plugin]; - if(lt.mIndex + 1 > (int)ltexl.size()) - ltexl.resize(lt.mIndex+1); - - // Store it - ltexl[lt.mIndex] = lt; - } - - // Load all terrain palettes at the same size. Inherited virtual function - // from "RecList". Mostly useless, because we need the implementation - // above this one. - void load(ESMReader &esm, const std::string &id) - { - size_t plugin = esm.getIndex(); - load(esm, id, plugin); - } - }; - - /* Landscapes are indexed by the X,Y coordinates of the exterior - cell they belong to. - */ - struct LandList : RecList - { - virtual ~LandList() - { - for ( LandMap::iterator itr = lands.begin(); itr != lands.end(); ++itr ) - { - delete itr->second; - } - } - - // Map containing all landscapes - typedef std::pair LandCoord; - typedef std::map LandMap; - LandMap lands; - - int count; - LandList() : count(0) {} - int getSize() { return count; } - - virtual void listIdentifier (std::vector& identifier) const {} - - // Find land for the given coordinates. Return null if no mData. - Land *search(int x, int y) const - { - LandMap::const_iterator itr = lands.find(std::make_pair (x, y)); - if ( itr == lands.end() ) - { - return NULL; - } - - return itr->second; - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - - // Create the structure and load it. This actually skips the - // landscape data and remembers the file position for later. - Land *land = new Land(); - land->load(esm); - - // Store the structure - lands[std::make_pair (land->mX, land->mY)] = land; - } - }; - - struct ciLessBoost : std::binary_function -{ - bool operator() (const std::string & s1, const std::string & s2) const { - //case insensitive version of is_less - return lexicographical_compare(s1, s2, is_iless()); - } -}; - - - // Cells aren't simply indexed by name. Exterior cells are treated - // separately. - // TODO: case handling (cell names are case-insensitive, but they are also showen to the - // player, so we can't simply smash case. - struct CellList : RecList - { - // Total cell count. Used for statistics. - int count; - CellList() : count(0) {} - int getSize() { return count; } - - // List of interior cells. Indexed by cell name. - typedef std::map IntCells; - IntCells intCells; - - // List of exterior cells. Indexed as extCells[mX][mY]. - typedef std::map, ESM::Cell*> ExtCells; - ExtCells extCells; - - virtual void listIdentifier (std::vector& identifier) const - { - for (IntCells::const_iterator iter (intCells.begin()); iter!=intCells.end(); ++iter) - identifier.push_back (iter->first); - } - - virtual ~CellList() - { - for (IntCells::iterator it = intCells.begin(); it!=intCells.end(); ++it) - delete it->second; - - for (ExtCells::iterator it = extCells.begin(); it!=extCells.end(); ++it) - delete it->second; - } - - const ESM::Cell* searchInt(const std::string &id) const - { - IntCells::const_iterator iter = intCells.find(id); - - if (iter!=intCells.end()) - return iter->second; - - return 0; - } - - const ESM::Cell* findInt(const std::string &id) const - { - const ESM::Cell *cell = searchInt (id); - - if (!cell) - throw std::runtime_error ("Interior cell not found - " + id); - - return cell; - } - - const ESM::Cell *searchExt (int x, int y) const - { - ExtCells::const_iterator it = extCells.find (std::make_pair (x, y)); - - if (it==extCells.end()) - return 0; - - return it->second; - } - - const ESM::Cell *findExt (int x, int y) const - { - const ESM::Cell *cell = searchExt (x, y); - - if (!cell) - throw std::runtime_error ("Exterior cell not found"); - - return cell; - } - const ESM::Cell *searchExtByName (const std::string& id) const - { - for (ExtCells::const_iterator iter = extCells.begin(); iter!=extCells.end(); ++iter) - { - if (toLower (iter->second->mName) == toLower (id)) - return iter->second; - } - - return 0; - } - - const ESM::Cell *searchExtByRegion (const std::string& id) const - { - std::string id2 = toLower (id); - - for (ExtCells::const_iterator iter = extCells.begin(); iter!=extCells.end(); ++iter) - if (toLower (iter->second->mRegion)==id) - return iter->second; - - return 0; - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - - // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, - // and we merge all this data into one Cell object. However, we can't simply search for the cell id, - // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they - // are not available until both cells have been loaded! So first, proceed as usual. - - // All cells have a name record, even nameless exterior cells. - ESM::Cell *cell = new ESM::Cell; - cell->mName = id; - - // The cell itself takes care of all the hairy details - cell->load(esm); - - if(cell->mData.mFlags & ESM::Cell::Interior) - { - // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(searchInt(id)); - if (oldcell) { - cell->mContextList.push_back(oldcell->mContextList.at(0)); - delete oldcell; - } - intCells[id] = cell; - } - else - { - // Store exterior cells by grid position, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(searchExt(cell->getGridX(), cell->getGridY())); - if (oldcell) { - // The load order is important. Push the new source context on the *back* of the existing list, - // and then move the list to the new cell. - oldcell->mContextList.push_back(cell->mContextList.at(0)); - cell->mContextList = oldcell->mContextList; - delete oldcell; - } - extCells[std::make_pair (cell->mData.mX, cell->mData.mY)] = cell; - } - } - }; - - struct PathgridList : RecList - { - int count; - - // List of grids for interior cells. Indexed by cell name. - typedef std::map IntGrids; - IntGrids intGrids; - - // List of grids for exterior cells. Indexed as extCells[mX][mY]. - typedef std::map, ESM::Pathgrid*> ExtGrids; - ExtGrids extGrids; - - PathgridList() : count(0) {} - - virtual ~PathgridList() - { - for (IntGrids::iterator it = intGrids.begin(); it!=intGrids.end(); ++it) - delete it->second; - - for (ExtGrids::iterator it = extGrids.begin(); it!=extGrids.end(); ++it) - delete it->second; - } - - int getSize() { return count; } - - virtual void listIdentifier (std::vector& identifier) const - { - // do nothing - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - ESM::Pathgrid *grid = new ESM::Pathgrid; - grid->load(esm); - if (grid->mData.mX == 0 && grid->mData.mY == 0) - { - intGrids[grid->mCell] = grid; - } - else - { - extGrids[std::make_pair(grid->mData.mX, grid->mData.mY)] = grid; - } - } - - Pathgrid *find(int cellX, int cellY, const std::string &cellName) const - { - Pathgrid *result = search(cellX, cellY, cellName); - if (!result) - { - throw std::runtime_error("no pathgrid found for cell " + cellName); - } - return result; - } - - Pathgrid *search(int cellX, int cellY, const std::string &cellName) const - { - Pathgrid *result = NULL; - if (cellX == 0 && cellY == 0) // possibly interior - { - IntGrids::const_iterator it = intGrids.find(cellName); - if (it != intGrids.end()) - result = it->second; - } - else - { - ExtGrids::const_iterator it = extGrids.find(std::make_pair(cellX, cellY)); - if (it != extGrids.end()) - result = it->second; - } - return result; - } - - Pathgrid *search(const ESM::Cell &cell) const - { - int cellX, cellY; - if (cell.mData.mFlags & ESM::Cell::Interior) - { - cellX = cellY = 0; - } - else - { - cellX = cell.mData.mX; - cellY = cell.mData.mY; - } - return search(cellX, cellY, cell.mName); - } - }; - - template - struct ScriptListT : RecList - { - virtual ~ScriptListT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - X ref; - ref.load (esm); - - std::string realId = toLower (ref.mData.mName.toString()); - - std::swap (list[realId], ref); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - template - struct IndexListT - { - virtual ~IndexListT() {} - - typedef std::map MapType; - - MapType list; - - void load(ESMReader &esm) - { - X ref; - ref.load (esm); - int index = ref.mIndex; - list[index] = ref; - } - - int getSize() - { - return list.size(); - } - - virtual void listIdentifier (std::vector& identifier) const {} - - // Find the given object ID, or return NULL if not found. - const X* search (int id) const - { - typename MapType::const_iterator iter = list.find (id); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find (int id) const - { - const X *object = search (id); - - if (!object) - { - std::ostringstream error; - error << "object " << id << " not found"; - throw std::runtime_error (error.str()); - } - - return object; - } - }; - - /* We need special lists for: - - Path grids - */ -} -#endif diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp deleted file mode 100644 index aeacfbacdc..0000000000 --- a/components/esm_store/store.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include "store.hpp" - -using namespace std; -using namespace ESM; -using namespace ESMS; - -/* -static string toStr(int i) -{ - char name[5]; - *((int*)name) = i; - name[4] = 0; - return std::string(name); -} -*/ - -void ESMStore::load(ESMReader &esm) -{ - set missing; - - ESM::Dialogue *dialogue = 0; - - // Loop through all records - while(esm.hasMoreRecs()) - { - NAME n = esm.getRecName(); - esm.getRecHeader(); - - // Look up the record type. - RecListList::iterator it = recLists.find(n.val); - - if(it == recLists.end()) - { - if (n.val==ESM::REC_INFO) - { - if (dialogue) - { - ESM::DialInfo info; - info.load (esm); - - dialogue->mInfo.push_back (info); - } - else - { - std::cerr << "error: info record without dialog" << std::endl; - esm.skipRecord(); - } - } - else if (n.val==ESM::REC_MGEF) - { - magicEffects.load (esm); - } - else if (n.val==ESM::REC_SKIL) - { - skills.load (esm); - } - else - { - // Not found (this would be an error later) - esm.skipRecord(); - missing.insert(n.toString()); - } - } - else - { - // Load it - std::string id = esm.getHNOString("NAME"); - // ... unless it got deleted! This means that the following record - // has been deleted, and trying to load it using standard assumptions - // on the structure will (probably) fail. - 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) - { - RecListCaseT& recList = static_cast& > (*it->second); - - ESM::Dialogue* d = recList.search (id); - - assert (d != NULL); - - dialogue = d; - } - else - dialogue = 0; - - // Insert the reference into the global lookup - if(!id.empty() && - (n.val==REC_ACTI || n.val==REC_ALCH || n.val==REC_APPA || n.val==REC_ARMO || - n.val==REC_BOOK || n.val==REC_CLOT || n.val==REC_CONT || n.val==REC_CREA || - n.val==REC_DOOR || n.val==REC_INGR || n.val==REC_LEVC || n.val==REC_LEVI || - n.val==REC_LIGH || n.val==REC_LOCK || n.val==REC_MISC || n.val==REC_NPC_ || - n.val==REC_PROB || n.val==REC_REPA || n.val==REC_STAT || n.val==REC_WEAP) - ) - all[id] = n.val; - } - } - - for (int i = 0; i < Attribute::Length; ++i) - { - Attribute::AttributeID id = Attribute::sAttributeIds[i]; - attributes.list.insert(std::make_pair(id, Attribute(id, Attribute::sGmstAttributeIds[i], Attribute::sGmstAttributeDescIds[i]))); - } - - /* This information isn't needed on screen. But keep the code around - for debugging purposes later. - - cout << "\n" << recLists.size() << " record types:\n"; - for(RecListList::iterator it = recLists.begin(); it != recLists.end(); it++) - cout << " " << toStr(it->first) << ": " << it->second->getSize() << endl; - cout << "\nNot implemented yet: "; - for(set::iterator it = missing.begin(); - it != missing.end(); it++ ) - cout << *it << " "; - cout << endl; - */ -} From b7b51f24d63696436157086ed79356704889d084 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Jan 2013 11:20:25 +0100 Subject: [PATCH 0011/1483] added new Role for table headers (Role_Display) --- apps/opencs/model/world/columnbase.cpp | 4 ++-- apps/opencs/model/world/columnbase.hpp | 18 ++++++++++++++---- apps/opencs/model/world/columns.hpp | 9 +++++---- apps/opencs/model/world/idtable.cpp | 3 +++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 7adc7e6c3a..134c582c40 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -1,8 +1,8 @@ #include "columnbase.hpp" -CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags) -: mTitle (title), mFlags (flags) +CSMWorld::ColumnBase::ColumnBase (const std::string& title, Display displayType, int flags) +: mTitle (title), mDisplayType (displayType), mFlags (flags) {} CSMWorld::ColumnBase::~ColumnBase() {} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index dc077eff60..38b73ee3f5 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -14,7 +14,8 @@ namespace CSMWorld { enum Roles { - Role_Flags = Qt::UserRole + Role_Flags = Qt::UserRole, + Role_Display = Qt::UserRole+1 }; enum Flags @@ -23,10 +24,18 @@ namespace CSMWorld Flag_Dialogue = 2 // column should be displayed in dialogue view }; + enum Display + { + Display_String, + Display_Integer, + Display_Float + }; + std::string mTitle; int mFlags; + Display mDisplayType; - ColumnBase (const std::string& title, int flag); + ColumnBase (const std::string& title, Display displayType, int flag); virtual ~ColumnBase(); @@ -34,6 +43,7 @@ namespace CSMWorld virtual bool isUserEditable() const; ///< Can this column be edited directly by the user? + }; template @@ -42,8 +52,8 @@ namespace CSMWorld std::string mTitle; int mFlags; - Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue) - : ColumnBase (title, flags) {} + Column (const std::string& title, Display displayType, int flags = Flag_Table | Flag_Dialogue) + : ColumnBase (title, displayType, flags) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 5abf4ea8bc..1e2de92658 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -8,7 +8,7 @@ namespace CSMWorld template struct FloatValueColumn : public Column { - FloatValueColumn() : Column ("Value") {} + FloatValueColumn() : Column ("Value", ColumnBase::Display_Float) {} virtual QVariant get (const Record& record) const { @@ -31,7 +31,7 @@ namespace CSMWorld template struct StringIdColumn : public Column { - StringIdColumn() : Column ("ID") {} + StringIdColumn() : Column ("ID", ColumnBase::Display_String) {} virtual QVariant get (const Record& record) const { @@ -47,7 +47,7 @@ namespace CSMWorld template struct RecordStateColumn : public Column { - RecordStateColumn() : Column ("*") {} + RecordStateColumn() : Column ("*", ColumnBase::Display_Integer) {} virtual QVariant get (const Record& record) const { @@ -78,7 +78,8 @@ namespace CSMWorld { int mType; - FixedRecordTypeColumn (int type) : Column ("Type", 0), mType (type) {} + FixedRecordTypeColumn (int type) + : Column ("Type", ColumnBase::Display_Integer, 0), mType (type) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2815e318c8..afed6b6eda 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -51,6 +51,9 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation if (role==ColumnBase::Role_Flags) return mIdCollection->getColumn (section).mFlags; + if (role==ColumnBase::Role_Display) + return mIdCollection->getColumn (section).mDisplayType; + return QVariant(); } From d6377fb2e39ef8d25fd887511d7f0bc501f00b59 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Thu, 3 Jan 2013 18:51:04 +0100 Subject: [PATCH 0012/1483] - Support deleting references from a plugin - Add preliminary support for loading some unique fields appearing only in savegames - Add a few lines required for supporting respawning references. Incomplete. --- apps/openmw/mwworld/cellstore.cpp | 7 +++++-- apps/openmw/mwworld/cellstore.hpp | 7 +++++++ components/esm/esmreader.hpp | 8 ++++++++ components/esm/loadcell.cpp | 28 ++++++++++++++++++++++++++-- components/esm/loadcell.hpp | 3 +++ 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ba8f5aa613..d007ff9811 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -61,11 +61,15 @@ namespace MWWorld while (mCell->getNextRef (esm[index], ref)) { std::string lowerCase; + if (ref.mDeleted) { + // Right now, don't do anything. Wehere is "listRefs" actually used, anyway? + // Skipping for now... + continue; + } std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: Fully support deletion of references. mIds.push_back (lowerCase); } } @@ -97,7 +101,6 @@ namespace MWWorld std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: Fully support deletion of references. int rec = store.find(ref.mRefID); ref.mRefID = lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cf09496e87..2b25faa70f 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -59,6 +59,13 @@ namespace MWWorld /// on miss void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) { + // Skip this when reference was deleted. + // TODO: Support respawning references, in this case, we need to track it somehow. + if (ref.mDeleted) { + mList.erase(ref.mRefnum); + return; + } + // for throwing exception on unhandled record type const MWWorld::Store &store = esmStore.get(); const X *ptr = store.search(ref.mRefID); diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 732dbe9bc6..df4c1919e8 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -119,6 +119,14 @@ public: getHT(x); } + template + void getHNOT(X &x, const char* name, int size) + { + assert(sizeof(X) == size); + if(isNextSub(name)) + getHT(x); + } + int64_t getHNLong(const char *name); // Get data of a given type/size, including subrecord header diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index b7f27b08d0..aafe629e64 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -213,7 +213,24 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // missing ref.mScale = 1.0; esm.getHNOT(ref.mScale, "XSCL"); - + + // TODO: support loading references from saves, there are tons of keys not recognized yet. + // The following is just an incomplete list. + if (esm.isNextSub("ACTN")) + esm.skipHSub(); + if (esm.isNextSub("STPR")) + esm.skipHSub(); + if (esm.isNextSub("ACDT")) + esm.skipHSub(); + if (esm.isNextSub("ACSC")) + esm.skipHSub(); + if (esm.isNextSub("ACSL")) + esm.skipHSub(); + if (esm.isNextSub("CHRD")) + esm.skipHSub(); + else if (esm.isNextSub("CRED")) // ??? + esm.skipHSub(); + ref.mOwner = esm.getHNOString("ANAM"); ref.mGlob = esm.getHNOString("BNAM"); ref.mSoul = esm.getHNOString("XSOL"); @@ -251,7 +268,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNOT(ref.mUnam, "UNAM"); esm.getHNOT(ref.mFltv, "FLTV"); - esm.getHNT(ref.mPos, "DATA", 24); + esm.getHNOT(ref.mPos, "DATA", 24); // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other @@ -265,6 +282,13 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHT(ref.mNam0); //esm.getHNOT(NAM0, "NAM0"); } + + if (esm.isNextSub("DELE")) { + esm.skipHSub(); + ref.mDeleted = 2; // Deleted, will not respawn. + // TODO: find out when references do respawn. + } else + ref.mDeleted = 0; return true; } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index ccfdcadd87..dff5a33387 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -70,6 +70,9 @@ public: // No idea - occurs ONCE in Morrowind.esm, for an activator char mUnam; + + // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. + int mDeleted; // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza // Brindisi Dorom", where it has the value 100. Also only for From 6e84d4bcdde03b821c6d880bda2d26b4dfbdf207 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 23:19:48 -0800 Subject: [PATCH 0013/1483] Add a helper method to load entity objects --- apps/openmw/mwrender/animation.cpp | 30 +++++++++++++++++++--- apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/creatureanimation.cpp | 15 +---------- apps/openmw/mwrender/npcanimation.cpp | 17 +----------- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2a3b8cf437..4784771a9d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -19,10 +19,34 @@ Animation::Animation() Animation::~Animation() { - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) - sceneMgr->destroyEntity(mEntityList.mEntities[i]); + if(mInsert) + { + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) + sceneMgr->destroyEntity(mEntityList.mEntities[i]); + } mEntityList.mEntities.clear(); + mEntityList.mSkelBase = NULL; +} + + +void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) +{ + mInsert = node; + assert(mInsert); + + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, model); + 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); + } + } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 07583db788..ebbfb2a7ac 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -43,6 +43,8 @@ protected: bool findGroupTimes(const std::string &groupname, GroupTimes *times); + void createEntityList(Ogre::SceneNode *node, const std::string &model); + public: Animation(); virtual ~Animation(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7ee361a6f6..1ca897c15e 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -18,7 +18,6 @@ CreatureAnimation::~CreatureAnimation() CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() { - mInsert = ptr.getRefData().getBaseNode(); MWWorld::LiveCellRef *ref = ptr.get(); assert (ref->mBase != NULL); @@ -26,7 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() { std::string mesh = "meshes\\" + ref->mBase->mModel; - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, mesh); + createEntityList(ptr.getRefData().getBaseNode(), mesh); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; @@ -52,18 +51,6 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() } 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); - } - } } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e6a8006e24..c76c67425b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -82,13 +82,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mBodyPrefix = "b_n_" + mNpc->mRace; std::transform(mBodyPrefix.begin(), mBodyPrefix.end(), mBodyPrefix.begin(), ::tolower); - mInsert = node; - assert(mInsert); - bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, smodel); + createEntityList(node, smodel); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *base = mEntityList.mEntities[i]; @@ -116,18 +113,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->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); - } - } - float scale = race->mData.mHeight.mMale; if (!mNpc->isMale()) { scale = race->mData.mHeight.mFemale; From 818a24cdd6542513d7b3f4133856cdc338b23822 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 00:03:14 -0800 Subject: [PATCH 0014/1483] Hold on to the AnimationState being used for animating --- apps/openmw/mwrender/animation.cpp | 15 +++++---------- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4784771a9d..6b8a3283cb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -14,6 +14,7 @@ Animation::Animation() : mInsert(NULL) , mTime(0.0f) , mSkipFrame(false) + , mAnimState(NULL) { } @@ -45,6 +46,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::AnimationState *state = as.getNext(); state->setEnabled(true); state->setLoop(false); + if(!mAnimState) + mAnimState = state; } } } @@ -155,16 +158,8 @@ void Animation::runAnimation(float 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(mAnimState) + mAnimState->setTimePosition(mTime); } mSkipFrame = false; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ebbfb2a7ac..de4778d876 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -40,6 +40,7 @@ protected: NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; + Ogre::AnimationState *mAnimState; bool findGroupTimes(const std::string &groupname, GroupTimes *times); From 761914bdaa3d02207afe13fbf36a3d3430fe8226 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 03:31:51 -0800 Subject: [PATCH 0015/1483] Use a separate method to build the animation --- components/nifogre/ogre_nif_loader.cpp | 228 +++++++++++++------------ 1 file changed, 115 insertions(+), 113 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 31d873489c..61e3a72e91 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -162,6 +162,120 @@ static void fail(const std::string &msg) } +static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) +{ + Ogre::Animation *anim = skel->createAnimation(name, stopTime); + /* 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 */ + const Nif::QuaternionKeyList &quatkeys = kf->mRotations; + const Nif::Vector3KeyList &trankeys = kf->mTranslations; + const Nif::FloatKeyList &scalekeys = kf->mScales; + + Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + + Ogre::Bone *bone = skel->getBone(targets[i]); + Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); + const Ogre::Quaternion startquat = bone->getInitialOrientation(); + const Ogre::Vector3 starttrans = bone->getInitialPosition(); + const Ogre::Vector3 startscale = bone->getInitialScale(); + + 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; + float begTime = std::max(kfc->timeStart, startTime); + float endTime = std::min(kfc->timeStop, stopTime); + bool didlast = false; + + while(!didlast) + { + float curtime = std::numeric_limits::max(); + + //Get latest time + 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, begTime); + if(curtime >= endTime) + { + didlast = true; + curtime = endTime; + } + + // Get the latest quaternions, translations, and scales for the + // current time + while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) + { + lastquat = curquat; + if(++quatiter != quatkeys.mKeys.end()) + curquat = startquat.Inverse() * quatiter->mValue; + } + while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) + { + lasttrans = curtrans; + if(++traniter != trankeys.mKeys.end()) + curtrans = traniter->mValue - starttrans; + } + while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) + { + lastscale = curscale; + if(++scaleiter != scalekeys.mKeys.end()) + curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + } + + Ogre::TransformKeyFrame *kframe; + kframe = nodetrack->createNodeKeyFrame(curtime); + if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) + kframe->setRotation(curquat); + else + { + Nif::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 + { + Nif::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 + { + Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; + float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); + kframe->setScale(lastscale + ((curscale-lastscale)*diff)); + } + } + } + anim->optimise(); +} + + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) { TextKeyMap textkeys; @@ -279,119 +393,7 @@ void loadResource(Ogre::Resource *resource) return; } - 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(); - 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 */ - Nif::QuaternionKeyList quatkeys = kf->mRotations; - Nif::Vector3KeyList trankeys = kf->mTranslations; - Nif::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()); - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::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; - - //Get latest time - 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 quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - quatiter++; - if(quatiter != quatkeys.mKeys.end()) - curquat = startquat.Inverse() * quatiter->mValue ; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - traniter++; - if(traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue - starttrans; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - scaleiter++; - if(scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue) / startscale; - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::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 - { - Nif::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 - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); + buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); } bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) From 58d35dbfcfef078f388cdf28dc1bd339df8fb3e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 04:01:11 -0800 Subject: [PATCH 0016/1483] Have createEntities' caller retrieve the text keys as needed --- apps/openmw/mwrender/animation.cpp | 19 ++++++++++++++-- apps/openmw/mwrender/objects.cpp | 2 +- components/nifogre/ogre_nif_loader.cpp | 30 ++++++-------------------- components/nifogre/ogre_nif_loader.hpp | 4 ++-- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6b8a3283cb..d2d253b919 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,6 +1,6 @@ #include "animation.hpp" -#include +#include #include #include #include @@ -36,7 +36,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mInsert = node; assert(mInsert); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, model); + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); @@ -49,6 +49,21 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!mAnimState) mAnimState = state; } + + // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + Ogre::SkeletonPtr skel = skelMgr.getByName(mEntityList.mSkelBase->getSkeleton()->getName()); + Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); + while(iter.hasMoreElements()) + { + Ogre::Bone *bone = iter.getNext(); + const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); + if(!data.isEmpty()) + { + mTextKeys = Ogre::any_cast(data); + break; + } + } } } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 36f09e6d96..ae188c11ef 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -94,7 +94,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, NULL, mesh); + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) { const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 61e3a72e91..f579b4b932 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -329,7 +329,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorrecType == Nif::RC_NiTextKeyExtraData) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - bone->getUserObjectBindings().setUserAny("TextKeyExtraData", Ogre::Any(extractTextKeys(tk))); + bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(extractTextKeys(tk))); } e = e->extra; } @@ -1083,7 +1083,7 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textkeys, const std::string &name, const std::string &group) +EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group) { EntityList entitylist; @@ -1091,7 +1091,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke if(meshes.size() == 0) return entitylist; - Ogre::SceneManager *sceneMgr = parent->getCreator(); + Ogre::SceneManager *sceneMgr = parentNode->getCreator(); for(size_t i = 0;i < meshes.size();i++) { entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first)); @@ -1100,34 +1100,16 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke entitylist.mSkelBase = entity; } - if(entitylist.mSkelBase && textkeys) - { - // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(entitylist.mSkelBase->getSkeleton()->getName()); - Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); - while(iter.hasMoreElements()) - { - Ogre::Bone *bone = iter.getNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny("TextKeyExtraData"); - if(!data.isEmpty()) - { - *textkeys = Ogre::any_cast(data); - break; - } - } - } - if(entitylist.mSkelBase) { - parent->attachObject(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(entitylist.mSkelBase); - parent->attachObject(entity); + parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); @@ -1136,7 +1118,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke else { for(size_t i = 0;i < entitylist.mEntities.size();i++) - parent->attachObject(entitylist.mEntities[i]); + parentNode->attachObject(entitylist.mEntities[i]); } return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 3e05c58734..9dcd0bea66 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -43,6 +43,7 @@ namespace NifOgre // FIXME: These should not be in NifOgre, it works agnostic of what model format is used typedef std::multimap TextKeyMap; +static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { std::vector mEntities; Ogre::Entity *mSkelBase; @@ -77,8 +78,7 @@ public: const std::string &name, const std::string &group="General"); - static EntityList createEntities(Ogre::SceneNode *parent, - TextKeyMap *textkeys, + static EntityList createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group="General"); }; From e5ce55b6a4b4a88d75203c5c73b832310b0757aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 06:20:21 -0800 Subject: [PATCH 0017/1483] Remove a hack --- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index f579b4b932..870b8df0ee 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -165,11 +165,6 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { Ogre::Animation *anim = skel->createAnimation(name, stopTime); - /* 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++) { @@ -186,10 +181,12 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); Ogre::Bone *bone = skel->getBone(targets[i]); - Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); - const Ogre::Quaternion startquat = bone->getInitialOrientation(); - const Ogre::Vector3 starttrans = bone->getInitialPosition(); - const Ogre::Vector3 startscale = bone->getInitialScale(); + // NOTE: For some reason, Ogre doesn't like the node track ID being different from + // the bone ID + Ogre::NodeAnimationTrack *nodetrack = anim->createNodeTrack(bone->getHandle(), bone); + const Ogre::Quaternion &startquat = bone->getInitialOrientation(); + const Ogre::Vector3 &starttrans = bone->getInitialPosition(); + const Ogre::Vector3 &startscale = bone->getInitialScale(); Ogre::Quaternion lastquat, curquat; Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); From 18389c7b04213bf56987db8fa9b6d29365a090ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 17:50:22 -0800 Subject: [PATCH 0018/1483] Set non-bone nodes as manually controlled --- 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 870b8df0ee..f1aecf720b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -306,11 +306,12 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorcreateBone(); if(parent) parent->addChild(bone); + if(!node->boneTrafo) + bone->setManuallyControlled(true); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); bone->setScale(Ogre::Vector3(node->trafo.scale)); bone->setBindingPose(); - bone->setInitialState(); Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) From 8ebf49a35b643d61b36b5394203fe8cf5bf6f6b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 20:54:57 -0800 Subject: [PATCH 0019/1483] Only lower-case the model name The skeleton name will already be lower-case --- components/nifogre/ogre_nif_loader.cpp | 12 +++++------- components/nifogre/ogre_nif_loader.hpp | 8 +++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index f1aecf720b..04b2822e02 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1043,11 +1043,8 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshPairMap; static MeshPairMap sMeshPairMap; -MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group) +MeshPairList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) { - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - std::transform(skelName.begin(), skelName.end(), skelName.begin(), ::tolower); - MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName); if(meshiter != sMeshPairMap.end()) return meshiter->second; @@ -1081,10 +1078,11 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group) +EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); MeshPairList meshes = load(name, name, group); if(meshes.size() == 0) return entitylist; @@ -1124,11 +1122,11 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::str EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, - const std::string &name, - const std::string &group) + std::string name, const std::string &group) { EntityList entitylist; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); if(meshes.size() == 0) return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 9dcd0bea66..47d1573fe7 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -70,21 +70,19 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(std::string name, std::string skelName, const std::string &group); + static MeshPairList load(const std::string &name, const std::string &skelName, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, - const std::string &name, + std::string name, const std::string &group="General"); static EntityList createEntities(Ogre::SceneNode *parentNode, - const std::string &name, + std::string name, const std::string &group="General"); }; } #endif - - From efca5ded472f6ea9a0a86f80257d1ab2191a10eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 21:12:08 -0800 Subject: [PATCH 0020/1483] Clean up some header includes to reduce nesting --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 1 + apps/openmw/mwclass/creature.hpp | 4 +--- apps/openmw/mwrender/actors.cpp | 13 ++++++++++--- apps/openmw/mwrender/actors.hpp | 16 +++++++++------- apps/openmw/mwrender/animation.hpp | 15 ++++----------- apps/openmw/mwrender/characterpreview.cpp | 1 + apps/openmw/mwrender/creatureanimation.hpp | 17 ++++++++++------- apps/openmw/mwrender/npcanimation.hpp | 9 +++++---- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- apps/openmw/mwworld/scene.cpp | 1 + 11 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cc625b3067..0c9110ed49 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -6,6 +6,7 @@ #include #include "../mwworld/globals.hpp" +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -42,7 +43,6 @@ namespace MWWorld class CellStore; class Player; class LocalScripts; - class Ptr; class TimeStamp; class ESMStore; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index edf5dd25d6..7b0f9f7289 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -18,6 +18,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/actors.hpp" #include "../mwgui/tooltips.hpp" diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index a158fa743e..a96c18a8c5 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,9 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "../mwrender/renderinginterface.hpp" -#include "../mwrender/actors.hpp" - +#include "../mwworld/class.hpp" namespace MWClass { diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 05bb030d70..fc5a46d12b 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -3,15 +3,20 @@ #include #include +#include "../mwworld/ptr.hpp" + +#include "animation.hpp" +#include "creatureanimation.hpp" +#include "npcanimation.hpp" + #include "renderconst.hpp" +namespace MWRender +{ using namespace Ogre; -using namespace MWRender; -using namespace NifOgre; Actors::~Actors(){ - std::map::iterator it = mAllActors.begin(); for (; it != mAllActors.end(); ++it) { delete it->second; @@ -156,3 +161,5 @@ Actors::updateObjectCell(const MWWorld::Ptr &ptr) mAllActors[ptr] = anim; } } + +} diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 073c5d51f1..71be0bd7b7 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -1,25 +1,27 @@ #ifndef _GAME_RENDER_ACTORS_H #define _GAME_RENDER_ACTORS_H -#include "npcanimation.hpp" -#include "creatureanimation.hpp" +#include namespace MWWorld { class Ptr; class CellStore; + class InventoryStore; } -namespace MWRender{ - class Actors{ +namespace MWRender +{ + class Animation; + + class Actors + { OEngine::Render::OgreRenderer &mRend; std::map mCellSceneNodes; Ogre::SceneNode* mMwRoot; std::map mAllActors; - - - public: + public: Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); void setMwRoot(Ogre::SceneNode* root); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index de4778d876..633a3f9e7a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,20 +1,13 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H -#include - #include -#include -#include "../mwworld/actiontalk.hpp" -#include -#include +namespace MWRender +{ - - -namespace MWRender { - -class Animation { +class Animation +{ struct GroupTimes { float mStart; float mStop; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 0a11dc2814..b144466c96 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" #include "renderconst.hpp" #include "npcanimation.hpp" diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index e1a7bbb8f4..5456f857f7 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -3,18 +3,21 @@ #include "animation.hpp" -#include "components/nifogre/ogre_nif_loader.hpp" +namespace MWWorld +{ + class Ptr; +} - -namespace MWRender{ - - class CreatureAnimation: public Animation +namespace MWRender +{ + class CreatureAnimation : public Animation { public: - virtual ~CreatureAnimation(); CreatureAnimation(const MWWorld::Ptr& ptr); - virtual void runAnimation(float timepassed); + virtual ~CreatureAnimation(); + virtual void runAnimation(float timepassed); }; } + #endif diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ca76dcc222..ff853de715 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -3,9 +3,7 @@ #include "animation.hpp" -#include "components/nifogre/ogre_nif_loader.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwclass/npc.hpp" #include "../mwworld/containerstore.hpp" namespace ESM @@ -13,9 +11,11 @@ namespace ESM struct NPC; } -namespace MWRender{ +namespace MWRender +{ -class NpcAnimation: public Animation{ +class NpcAnimation : public Animation +{ private: MWWorld::InventoryStore& mInv; int mStateID; @@ -91,4 +91,5 @@ public: }; } + #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8cb8e9fa8b..71424aaeda 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -19,8 +19,9 @@ #include #include -#include "../mwworld/esmstore.hpp" #include +#include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6b9abf508b..6a6ad92d75 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -10,6 +10,7 @@ #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" +#include "class.hpp" #include "cellfunctors.hpp" From 99769879e30ce15a2eda7765eea6727f01a50b64 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 00:32:38 -0800 Subject: [PATCH 0021/1483] Fix some createEntities calls --- apps/openmw/mwrender/sky.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 60ecd43034..c8a6ca0eff 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -324,7 +324,7 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif"); + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { Entity* night1_ent = entities.mEntities[i]; @@ -349,7 +349,7 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, NULL, "meshes\\sky_atmosphere.nif"); + entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* atmosphere_ent = entities.mEntities[i]; @@ -363,7 +363,7 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(clouds_node, NULL, "meshes\\sky_clouds_01.nif"); + entities = NifOgre::NIFLoader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* clouds_ent = entities.mEntities[i]; From 976b042cca0891e3a21b59af2795b4361e38534a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 01:59:18 -0800 Subject: [PATCH 0022/1483] Use a list to reduce some repeating code --- apps/openmw/mwrender/npcanimation.cpp | 264 ++++++++------------------ apps/openmw/mwrender/npcanimation.hpp | 12 +- 2 files changed, 88 insertions(+), 188 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c76c67425b..37c8aee647 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -14,34 +14,46 @@ using namespace Ogre; using namespace NifOgre; -namespace MWRender{ +namespace MWRender +{ + +const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { + { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, + { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, + { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, + { ESM::PRT_Cuirass, &NpcAnimation::mChest, "Chest" }, + { ESM::PRT_Groin, &NpcAnimation::mGroin, "Groin" }, + { ESM::PRT_Skirt, &NpcAnimation::mSkirt, "Groin" }, + { ESM::PRT_RHand, &NpcAnimation::mHandR, "Right Hand" }, + { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, + { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, + { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, + { ESM::PRT_Shield, NULL, "" }, + { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, + { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, + { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, + { ESM::PRT_LUpperarm, &NpcAnimation::mUpperArmL, "Left Upper Arm" }, + { ESM::PRT_RFoot, &NpcAnimation::mFootR, "Right Foot" }, + { ESM::PRT_LFoot, &NpcAnimation::mFootL, "Left Foot" }, + { ESM::PRT_RAnkle, &NpcAnimation::mAnkleR, "Right Ankle" }, + { ESM::PRT_LAnkle, &NpcAnimation::mAnkleL, "Left Ankle" }, + { ESM::PRT_RKnee, &NpcAnimation::mKneeR, "Right Knee" }, + { ESM::PRT_LKnee, &NpcAnimation::mKneeL, "Left Knee" }, + { ESM::PRT_RLeg, &NpcAnimation::mUpperLegR, "Right Upper Leg" }, + { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, + { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, + { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, + { ESM::PRT_Weapon, NULL, "" }, + { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } +}; + NpcAnimation::~NpcAnimation() { - removeEntities(mHead); - removeEntities(mHair); - removeEntities(mNeck); - removeEntities(mChest); - removeEntities(mGroin); - removeEntities(mSkirt); - removeEntities(mHandL); - removeEntities(mHandR); - removeEntities(mWristL); - removeEntities(mWristR); - removeEntities(mForearmL); - removeEntities(mForearmR); - removeEntities(mUpperArmL); - removeEntities(mUpperArmR); - removeEntities(mFootL); - removeEntities(mFootR); - removeEntities(mAnkleL); - removeEntities(mAnkleR); - removeEntities(mKneeL); - removeEntities(mKneeR); - removeEntities(mUpperLegL); - removeEntities(mUpperLegR); - removeEntities(mClavicleL); - removeEntities(mClavicleR); - removeEntities(mTail); + for(size_t i = 0;i < sPartListSize;i++) + { + if(sPartList[i].ents) + removeEntities(this->*sPartList[i].ents); + } } @@ -90,9 +102,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor { Ogre::Entity *base = mEntityList.mEntities[i]; - base->getUserObjectBindings ().setUserAny (Ogre::Any(-1)); - + base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); base->setVisibilityFlags(mVisibilityFlags); + bool transparent = false; for(unsigned int j=0;j < base->getNumSubEntities();++j) { @@ -126,29 +138,29 @@ void NpcAnimation::updateParts() { bool apparelChanged = false; - const struct { - MWWorld::ContainerStoreIterator *iter; + static const struct { + MWWorld::ContainerStoreIterator NpcAnimation::*iter; int slot; } slotlist[] = { - { &mRobe, MWWorld::InventoryStore::Slot_Robe }, - { &mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, - { &mHelmet, MWWorld::InventoryStore::Slot_Helmet }, - { &mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, - { &mGreaves, MWWorld::InventoryStore::Slot_Greaves }, - { &mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, - { &mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, - { &mBoots, MWWorld::InventoryStore::Slot_Boots }, - { &mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, - { &mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, - { &mShirt, MWWorld::InventoryStore::Slot_Shirt }, - { &mPants, MWWorld::InventoryStore::Slot_Pants }, + { &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe }, + { &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, + { &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet }, + { &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, + { &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves }, + { &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, + { &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, + { &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots }, + { &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, + { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt }, + { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants }, }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(*slotlist[i].iter != iter) + if(this->*slotlist[i].iter != iter) { - *slotlist[i].iter = iter; + this->*slotlist[i].iter = iter; removePartGroup(slotlist[i].slot); apparelChanged = true; } @@ -318,21 +330,18 @@ void NpcAnimation::updateParts() if(mPartPriorities[PartTypeList[i].type] < 1) { const ESM::BodyPart *part = NULL; - const MWWorld::Store &partStore = - store.get(); + const MWWorld::Store &partStore = store.get(); - if (!mNpc->isMale()) { + if(!mNpc->isMale()) + { part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); - } } - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); - } - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); - } if(part) addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); @@ -348,7 +357,7 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int for(size_t i = 0;i < parts.size();i++) { parts[i]->setVisibilityFlags(mVisibilityFlags); - parts[i]->getUserObjectBindings ().setUserAny (Ogre::Any(group)); + parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); } return entities; } @@ -384,62 +393,15 @@ void NpcAnimation::removeIndividualPart(int type) mPartPriorities[type] = 0; mPartslots[type] = -1; - if(type == ESM::PRT_Head) //0 - removeEntities(mHead); - else if(type == ESM::PRT_Hair) //1 - removeEntities(mHair); - else if(type == ESM::PRT_Neck) //2 - removeEntities(mNeck); - else if(type == ESM::PRT_Cuirass)//3 - removeEntities(mChest); - else if(type == ESM::PRT_Groin)//4 - removeEntities(mGroin); - else if(type == ESM::PRT_Skirt)//5 - removeEntities(mSkirt); - else if(type == ESM::PRT_RHand)//6 - removeEntities(mHandR); - else if(type == ESM::PRT_LHand)//7 - removeEntities(mHandL); - else if(type == ESM::PRT_RWrist)//8 - removeEntities(mWristR); - else if(type == ESM::PRT_LWrist) //9 - removeEntities(mWristL); - else if(type == ESM::PRT_Shield) //10 + for(size_t i = 0;i < sPartListSize;i++) { + if(type == sPartList[i].type) + { + if(sPartList[i].ents) + removeEntities(this->*sPartList[i].ents); + break; + } } - else if(type == ESM::PRT_RForearm) //11 - removeEntities(mForearmR); - else if(type == ESM::PRT_LForearm) //12 - removeEntities(mForearmL); - else if(type == ESM::PRT_RUpperarm) //13 - removeEntities(mUpperArmR); - else if(type == ESM::PRT_LUpperarm) //14 - removeEntities(mUpperArmL); - else if(type == ESM::PRT_RFoot) //15 - removeEntities(mFootR); - else if(type == ESM::PRT_LFoot) //16 - removeEntities(mFootL); - else if(type == ESM::PRT_RAnkle) //17 - removeEntities(mAnkleR); - else if(type == ESM::PRT_LAnkle) //18 - removeEntities(mAnkleL); - else if(type == ESM::PRT_RKnee) //19 - removeEntities(mKneeR); - else if(type == ESM::PRT_LKnee) //20 - removeEntities(mKneeL); - else if(type == ESM::PRT_RLeg) //21 - removeEntities(mUpperLegR); - else if(type == ESM::PRT_LLeg) //22 - removeEntities(mUpperLegL); - else if(type == ESM::PRT_RPauldron) //23 - removeEntities(mClavicleR); - else if(type == ESM::PRT_LPauldron) //24 - removeEntities(mClavicleL); - else if(type == ESM::PRT_Weapon) //25 - { - } - else if(type == ESM::PRT_Tail) //26 - removeEntities(mTail); } void NpcAnimation::reserveIndividualPart(int type, int group, int priority) @@ -469,87 +431,15 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, removeIndividualPart(type); mPartslots[type] = group; mPartPriorities[type] = priority; - switch(type) + + for(size_t i = 0;i < sPartListSize;i++) { - case ESM::PRT_Head: //0 - mHead = insertBoundedPart(mesh, group, "Head"); - break; - case ESM::PRT_Hair: //1 - mHair = insertBoundedPart(mesh, group, "Head"); - break; - case ESM::PRT_Neck: //2 - mNeck = insertBoundedPart(mesh, group, "Neck"); - break; - case ESM::PRT_Cuirass: //3 - mChest = insertBoundedPart(mesh, group, "Chest"); - break; - case ESM::PRT_Groin: //4 - mGroin = insertBoundedPart(mesh, group, "Groin"); - break; - case ESM::PRT_Skirt: //5 - mSkirt = insertBoundedPart(mesh, group, "Groin"); - break; - case ESM::PRT_RHand: //6 - mHandR = insertBoundedPart(mesh, group, "Right Hand"); - break; - case ESM::PRT_LHand: //7 - mHandL = insertBoundedPart(mesh, group, "Left Hand"); - break; - case ESM::PRT_RWrist: //8 - mWristR = insertBoundedPart(mesh, group, "Right Wrist"); - break; - case ESM::PRT_LWrist: //9 - mWristL = insertBoundedPart(mesh, group, "Left Wrist"); - break; - case ESM::PRT_Shield: //10 - break; - case ESM::PRT_RForearm: //11 - mForearmR = insertBoundedPart(mesh, group, "Right Forearm"); - break; - case ESM::PRT_LForearm: //12 - mForearmL = insertBoundedPart(mesh, group, "Left Forearm"); - break; - case ESM::PRT_RUpperarm: //13 - mUpperArmR = insertBoundedPart(mesh, group, "Right Upper Arm"); - break; - case ESM::PRT_LUpperarm: //14 - mUpperArmL = insertBoundedPart(mesh, group, "Left Upper Arm"); - break; - case ESM::PRT_RFoot: //15 - mFootR = insertBoundedPart(mesh, group, "Right Foot"); - break; - case ESM::PRT_LFoot: //16 - mFootL = insertBoundedPart(mesh, group, "Left Foot"); - break; - case ESM::PRT_RAnkle: //17 - mAnkleR = insertBoundedPart(mesh, group, "Right Ankle"); - break; - case ESM::PRT_LAnkle: //18 - mAnkleL = insertBoundedPart(mesh, group, "Left Ankle"); - break; - case ESM::PRT_RKnee: //19 - mKneeR = insertBoundedPart(mesh, group, "Right Knee"); - break; - case ESM::PRT_LKnee: //20 - mKneeL = insertBoundedPart(mesh, group, "Left Knee"); - break; - case ESM::PRT_RLeg: //21 - mUpperLegR = insertBoundedPart(mesh, group, "Right Upper Leg"); - break; - case ESM::PRT_LLeg: //22 - mUpperLegL = insertBoundedPart(mesh, group, "Left Upper Leg"); - break; - case ESM::PRT_RPauldron: //23 - mClavicleR = insertBoundedPart(mesh , group, "Right Clavicle"); - break; - case ESM::PRT_LPauldron: //24 - mClavicleL = insertBoundedPart(mesh, group, "Left Clavicle"); - break; - case ESM::PRT_Weapon: //25 - break; - case ESM::PRT_Tail: //26 - mTail = insertBoundedPart(mesh, group, "Tail"); + if(type == sPartList[i].type) + { + if(sPartList[i].ents) + this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); break; + } } return true; } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ff853de715..e6eee54916 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -14,6 +14,14 @@ namespace ESM namespace MWRender { +class NpcAnimation; + +struct PartInfo { + ESM::PartReferenceType type; + NifOgre::EntityList NpcAnimation::*ents; + const char name[32]; +}; + class NpcAnimation : public Animation { private: @@ -55,7 +63,6 @@ private: std::string mHairModel; std::string mBodyPrefix; - float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; MWWorld::ContainerStoreIterator mHelmet; @@ -72,6 +79,9 @@ private: int mVisibilityFlags; + static const size_t sPartListSize = 27; + static const PartInfo sPartList[sPartListSize]; + public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags); From 2b1fe7dc44652f1531fb9aa70c67a62cb19e6752 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 05:39:39 -0800 Subject: [PATCH 0023/1483] Add part info for weapons and shields --- apps/openmw/mwrender/npcanimation.cpp | 25 ++++++++++--------------- apps/openmw/mwrender/npcanimation.hpp | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 37c8aee647..b7e93cef2b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -17,7 +17,7 @@ using namespace NifOgre; namespace MWRender { -const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { +const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, @@ -28,7 +28,7 @@ const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, - { ESM::PRT_Shield, NULL, "" }, + { ESM::PRT_Shield, &NpcAnimation::mShield, "Shield" }, { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, @@ -43,24 +43,21 @@ const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, - { ESM::PRT_Weapon, NULL, "" }, + { ESM::PRT_Weapon, &NpcAnimation::mWeapon, "Weapon" }, { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } }; NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - { - if(sPartList[i].ents) - removeEntities(this->*sPartList[i].ents); - } + removeEntities(this->*sPartList[i].ents); } NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(), - mStateID(-1), mInv(inv), + mStateID(-1), mTimeToChange(0), mVisibilityFlags(visibilityFlags), mRobe(mInv.end()), @@ -78,10 +75,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor { mNpc = ptr.get()->mBase; - for (int init = 0; init < 27; init++) + for(size_t i = 0;i < sPartListSize;i++) { - mPartslots[init] = -1; //each slot is empty - mPartPriorities[init] = 0; + mPartslots[i] = -1; //each slot is empty + mPartPriorities[i] = 0; } const MWWorld::ESMStore &store = @@ -397,8 +394,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - if(sPartList[i].ents) - removeEntities(this->*sPartList[i].ents); + removeEntities(this->*sPartList[i].ents); break; } } @@ -436,8 +432,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - if(sPartList[i].ents) - this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); + this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index e6eee54916..090366a234 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -14,23 +14,22 @@ namespace ESM namespace MWRender { -class NpcAnimation; - +class NpcAnimation : public Animation +{ +public: struct PartInfo { ESM::PartReferenceType type; NifOgre::EntityList NpcAnimation::*ents; const char name[32]; }; -class NpcAnimation : public Animation -{ private: + static const size_t sPartListSize = 27; + static const PartInfo sPartList[sPartListSize]; + MWWorld::InventoryStore& mInv; int mStateID; - int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty - int mPartPriorities[27]; - //Bounded Parts NifOgre::EntityList mClavicleL; NifOgre::EntityList mClavicleR; @@ -54,6 +53,8 @@ private: NifOgre::EntityList mHair; NifOgre::EntityList mHandL; NifOgre::EntityList mHandR; + NifOgre::EntityList mShield; + NifOgre::EntityList mWeapon; NifOgre::EntityList mHead; NifOgre::EntityList mChest; NifOgre::EntityList mTail; @@ -79,8 +80,8 @@ private: int mVisibilityFlags; - static const size_t sPartListSize = 27; - static const PartInfo sPartList[sPartListSize]; + int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty + int mPartPriorities[sPartListSize]; public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, From b96a9797199d4fa076d6516d59e9a892d744e8c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 17:05:48 -0800 Subject: [PATCH 0024/1483] Store an MWWorld::Ptr with the Animation --- apps/openmw/mwrender/animation.cpp | 5 +++-- apps/openmw/mwrender/animation.hpp | 5 ++++- apps/openmw/mwrender/creatureanimation.cpp | 7 ++++--- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d2d253b919..d7f3d52d62 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,8 +10,9 @@ namespace MWRender { -Animation::Animation() - : mInsert(NULL) +Animation::Animation(const MWWorld::Ptr &ptr) + : mPtr(ptr) + , mInsert(NULL) , mTime(0.0f) , mSkipFrame(false) , mAnimState(NULL) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 633a3f9e7a..593538ea68 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -3,6 +3,8 @@ #include +#include "../mwworld/ptr.hpp" + namespace MWRender { @@ -23,6 +25,7 @@ class Animation }; protected: + MWWorld::Ptr mPtr; Ogre::SceneNode* mInsert; float mTime; @@ -40,7 +43,7 @@ protected: void createEntityList(Ogre::SceneNode *node, const std::string &model); public: - Animation(); + Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); void playGroup(std::string groupname, int mode, int loops); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 1ca897c15e..caa040d952 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -16,16 +16,17 @@ CreatureAnimation::~CreatureAnimation() { } -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) + : Animation(ptr) { - MWWorld::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = mPtr.get(); assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { std::string mesh = "meshes\\" + ref->mBase->mModel; - createEntityList(ptr.getRefData().getBaseNode(), mesh); + createEntityList(mPtr.getRefData().getBaseNode(), 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 b7e93cef2b..5682a86cc9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -55,7 +55,7 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) - : Animation(), + : Animation(ptr), mInv(inv), mStateID(-1), mTimeToChange(0), @@ -73,7 +73,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mGloveR(mInv.end()), mSkirtIter(mInv.end()) { - mNpc = ptr.get()->mBase; + mNpc = mPtr.get()->mBase; for(size_t i = 0;i < sPartListSize;i++) { From 910619eb21c05fc9baa93e139a7d011bce9ea775 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 17:31:53 -0800 Subject: [PATCH 0025/1483] Store the NonAccum animation root from the skeleton instance Currently this is assumed to be the node with the animation text keys. --- apps/openmw/mwrender/animation.cpp | 4 +++- apps/openmw/mwrender/animation.hpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d7f3d52d62..b8be879e58 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -14,8 +14,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mInsert(NULL) , mTime(0.0f) - , mSkipFrame(false) , mAnimState(NULL) + , mSkipFrame(false) + , mNonAccumRoot(NULL) { } @@ -62,6 +63,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); + mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getHandle()); break; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 593538ea68..3bc173d70a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,12 +31,13 @@ protected: float mTime; GroupTimes mCurGroup; GroupTimes mNextGroup; + Ogre::AnimationState *mAnimState; bool mSkipFrame; NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; - Ogre::AnimationState *mAnimState; + Ogre::Node *mNonAccumRoot; bool findGroupTimes(const std::string &groupname, GroupTimes *times); From 7ba09ff025e07250a88261a1b099f377717a72a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 20:05:50 -0800 Subject: [PATCH 0026/1483] Catch errors from buildBones --- components/nifogre/ogre_nif_loader.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 04b2822e02..3c8b3067a4 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -367,7 +367,14 @@ void loadResource(Ogre::Resource *resource) const Nif::Node *node = dynamic_cast(nif.getRecord(0)); std::vector ctrls; - buildBones(skel, node, ctrls); + try { + buildBones(skel, node, ctrls); + } + catch(std::exception &e) { + std::cerr<< "Exception while loading "<getName() < targets; // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file From 5b3a20ef69c23eea4f65b138aca43517c497963c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 21:18:48 -0800 Subject: [PATCH 0027/1483] Update the object position as the animation moves --- apps/openmw/mwrender/animation.cpp | 76 ++++++++++++++++++++--- apps/openmw/mwrender/animation.hpp | 11 +++- apps/openmw/mwrender/characterpreview.cpp | 1 - 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b8be879e58..b73d352644 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -7,6 +7,9 @@ #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + namespace MWRender { @@ -16,8 +19,14 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mTime(0.0f) , mAnimState(NULL) , mSkipFrame(false) + , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mLastPosition(0.0f) { + mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; + mCurGroup.mLoopStop = mCurGroup.mStop = 0.0f; + mNextGroup.mStart = mNextGroup.mLoopStart = 0.0f; + mNextGroup.mLoopStop = mNextGroup.mStop = 0.0f; } Animation::~Animation() @@ -52,9 +61,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAnimState = state; } + Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(mEntityList.mSkelBase->getSkeleton()->getName()); + Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); while(iter.hasMoreElements()) { @@ -63,7 +73,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); - mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getHandle()); + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); + mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mLastPosition = mNonAccumRoot->getPosition(); break; } } @@ -71,6 +84,43 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +void Animation::updatePosition(float time) +{ + mAnimState->setTimePosition(time); + if(mNonAccumRoot) + { + /* Update the animation and get the non-accumulation root's difference from the + * last update. */ + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; + + /* Translate the accumulation root back to compensate for the move. */ + mAccumRoot->translate(-posdiff); + mLastPosition += posdiff; + + /* Finally, move the object based on how much the non-accumulation root moved. */ + Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); + newpos += mInsert->getOrientation() * posdiff; + + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + } +} + +void Animation::resetPosition(float time) +{ + mAnimState->setTimePosition(time); + if(mNonAccumRoot) + { + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mLastPosition = mNonAccumRoot->getPosition(); + /* FIXME: This should be set to -mLastPosition, but without proper collision the + * model gets placed halfway into the ground. */ + mAccumRoot->setPosition(0.0f, 0.0f, 0.0f); + } +} + + struct checklow { bool operator()(const char &a, const char &b) const { @@ -145,6 +195,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup = times; mNextGroup = GroupTimes(); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); + resetPosition(mTime); } } @@ -155,29 +206,36 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mCurGroup.mLoops > 0 && !mSkipFrame) + if(mAnimState && !mSkipFrame) { mTime += timepassed; + recheck: if(mTime >= mCurGroup.mLoopStop) { if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; + updatePosition(mCurGroup.mLoopStop); mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart; + resetPosition(mCurGroup.mLoopStart); + goto recheck; } else if(mTime >= mCurGroup.mStop) { if(mNextGroup.mLoops > 0) + { + updatePosition(mCurGroup.mStop); mTime = mTime - mCurGroup.mStop + mNextGroup.mStart; - else - mTime = mCurGroup.mStop; - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); + resetPosition(mNextGroup.mStart); + mCurGroup = mNextGroup; + mNextGroup = GroupTimes(); + goto recheck; + } + mTime = mCurGroup.mStop; } } - if(mAnimState) - mAnimState->setTimePosition(mTime); + updatePosition(mTime); } mSkipFrame = false; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3bc173d70a..d1ae5af4c4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -37,7 +37,16 @@ protected: NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; - Ogre::Node *mNonAccumRoot; + Ogre::Bone *mAccumRoot; + Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mLastPosition; + + /* Updates the animation to the specified time, and moves the mPtr object + * based on the change since the last update or reset. */ + void updatePosition(float time); + /* Updates the animation to the specified time, without moving the mPtr + * object. */ + void resetPosition(float time); bool findGroupTimes(const std::string &groupname, GroupTimes *times); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b144466c96..7431c2a616 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -138,7 +138,6 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->playGroup ("inventoryhandtohand", 0, 1); - mAnimation->runAnimation (0); } // -------------------------------------------------------------------------------------------------- From 648e3331f51e5ee75176b82f72d3860e635548ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 23:20:20 -0800 Subject: [PATCH 0028/1483] Don't try to move objects that aren't in a cell --- apps/openmw/mwrender/animation.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b73d352644..4cf0db3ed5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,12 +98,15 @@ void Animation::updatePosition(float time) mAccumRoot->translate(-posdiff); mLastPosition += posdiff; - /* Finally, move the object based on how much the non-accumulation root moved. */ - Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); - newpos += mInsert->getOrientation() * posdiff; + if(mPtr.isInCell()) + { + /* Finally, move the object based on how much the non-accumulation root moved. */ + Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); + newpos += mInsert->getOrientation() * posdiff; - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + } } } From 14d814d1d310e6dd30ef5c82abfae036af585e94 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 04:21:25 -0800 Subject: [PATCH 0029/1483] Avoid creating bones for NiTriShape nodes The offset specified for them can be just as easilly handled by the tag point they get connected to, and as such it's just needless extra nodes. --- components/nifogre/ogre_nif_loader.cpp | 55 ++++++++++++++++---------- components/nifogre/ogre_nif_loader.hpp | 19 +++++++-- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 3c8b3067a4..e71c57efa7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -169,6 +169,8 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const for(size_t i = 0;i < ctrls.size();i++) { Nif::NiKeyframeController *kfc = ctrls[i]; + if(kfc->data.empty()) + continue; Nif::NiKeyframeData *kf = kfc->data.getPtr(); /* Get the keyframes and make sure they're sorted first to last */ @@ -183,7 +185,9 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Ogre::Bone *bone = skel->getBone(targets[i]); // NOTE: For some reason, Ogre doesn't like the node track ID being different from // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->createNodeTrack(bone->getHandle(), bone); + Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? + anim->getNodeTrack(bone->getHandle()) : + anim->createNodeTrack(bone->getHandle(), bone); const Ogre::Quaternion &startquat = bone->getInitialOrientation(); const Ogre::Vector3 &starttrans = bone->getInitialPosition(); const Ogre::Vector3 &startscale = bone->getInitialScale(); @@ -299,6 +303,9 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) { + if(node->recType == Nif::RC_NiTriShape) + return; + Ogre::Bone *bone; if(!skel->hasBone(node->name)) bone = skel->createBone(node->name); @@ -403,6 +410,9 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { + if(node->recType == Nif::RC_NiTriShape) + return false; + if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); @@ -733,7 +743,6 @@ 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(mSkelName); - 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 @@ -967,7 +976,7 @@ public: findTriShape(mesh, node); } - void createMeshes(const Nif::Node *node, MeshPairList &meshes, int flags=0) + void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) { flags |= node->flags; @@ -1026,7 +1035,8 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(std::make_pair(mesh->getName(), shape->name)); + meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), + shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); } else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && node->recType != Nif::RC_NiRotatingParticles) @@ -1047,16 +1057,16 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -typedef std::map MeshPairMap; -static MeshPairMap sMeshPairMap; +typedef std::map MeshInfoMap; +static MeshInfoMap sMeshInfoMap; -MeshPairList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) { - MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName); - if(meshiter != sMeshPairMap.end()) + MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); + if(meshiter != sMeshInfoMap.end()) return meshiter->second; - MeshPairList &meshes = sMeshPairMap[name+"@skel="+skelName]; + MeshInfoList &meshes = sMeshInfoMap[name+"@skel="+skelName]; Nif::NIFFile nif(name); if (nif.numRecords() < 1) { @@ -1090,14 +1100,14 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na EntityList entitylist; std::transform(name.begin(), name.end(), name.begin(), ::tolower); - MeshPairList meshes = load(name, name, group); + MeshInfoList meshes = load(name, name, group); if(meshes.size() == 0) return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); for(size_t i = 0;i < meshes.size();i++) { - entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first)); + entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].mMeshName)); Ogre::Entity *entity = entitylist.mEntities.back(); if(!entitylist.mSkelBase && entity->hasSkeleton()) entitylist.mSkelBase = entity; @@ -1115,7 +1125,12 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) - entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); + { + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + tag->setPosition(meshes[i].mPos); + tag->setOrientation(meshes[i].mRot); + tag->setScale(Ogre::Vector3(meshes[i].mScale)); + } } } else @@ -1134,22 +1149,22 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo EntityList entitylist; std::transform(name.begin(), name.end(), name.begin(), ::tolower); - MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); + MeshInfoList meshes = load(name, parent->getMesh()->getSkeletonName(), group); if(meshes.size() == 0) return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = "tri "+bonename; - std::transform(filter.begin()+4, filter.end(), filter.begin()+4, ::tolower); + std::string filter = bonename; + std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower); for(size_t i = 0;i < meshes.size();i++) { - Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first); + Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - std::transform(meshes[i].second.begin(), meshes[i].second.end(), meshes[i].second.begin(), ::tolower); + std::transform(meshes[i].mTargetNode.begin(), meshes[i].mTargetNode.end(), + meshes[i].mTargetNode.begin(), ::tolower); - if(meshes[i].second.length() < filter.length() || - meshes[i].second.compare(0, filter.length(), filter) != 0) + if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) { sceneMgr->destroyEntity(ent); continue; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 47d1573fe7..4ed52a84a7 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -53,8 +53,21 @@ struct EntityList { }; -/** This holds a list of mesh names along with the names of their parent nodes */ -typedef std::vector< std::pair > MeshPairList; +/* This holds a list of mesh names, the names of their parent nodes, and the offset + * from their parent nodes. */ +struct MeshInfo { + std::string mMeshName; + std::string mTargetNode; + Ogre::Vector3 mPos; + Ogre::Matrix3 mRot; + float mScale; + + MeshInfo(const std::string &name, const std::string &target, + const Ogre::Vector3 &pos, const Ogre::Matrix3 &rot, float scale) + : mMeshName(name), mTargetNode(target), mPos(pos), mRot(rot), mScale(scale) + { } +}; +typedef std::vector MeshInfoList; /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into @@ -70,7 +83,7 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(const std::string &name, const std::string &skelName, const std::string &group); + static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From 5f668976a84cbff41a948314f4e4282a8601b94d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 04:48:59 -0800 Subject: [PATCH 0030/1483] Improve resetting the animation position --- apps/openmw/mwrender/animation.cpp | 8 ++++---- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4cf0db3ed5..4b85804676 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,6 +21,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mSkipFrame(false) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mStartPosition(0.0f) , mLastPosition(0.0f) { mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; @@ -76,7 +77,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); - mLastPosition = mNonAccumRoot->getPosition(); + mStartPosition = mNonAccumRoot->getPosition(); + mLastPosition = mStartPosition; break; } } @@ -117,9 +119,7 @@ void Animation::resetPosition(float time) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); - /* FIXME: This should be set to -mLastPosition, but without proper collision the - * model gets placed halfway into the ground. */ - mAccumRoot->setPosition(0.0f, 0.0f, 0.0f); + mAccumRoot->setPosition(mStartPosition - mLastPosition); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d1ae5af4c4..73e34befeb 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -39,6 +39,7 @@ protected: NifOgre::TextKeyMap mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; /* Updates the animation to the specified time, and moves the mPtr object From 05dfafa7770d01f988f8d13488ab80df88d3e016 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:09:15 -0800 Subject: [PATCH 0031/1483] Avoid an unnecessary lookup when moving the scene node --- apps/openmw/mwrender/renderingmanager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 71424aaeda..51f1150ef7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -249,8 +249,7 @@ void RenderingManager::removeObject (const MWWorld::Ptr& ptr) void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position) { /// \todo move this to the rendering-subsystems - mRendering.getScene()->getSceneNode (ptr.getRefData().getHandle())-> - setPosition (position); + ptr.getRefData().getBaseNode()->setPosition(position); } void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale) From d3e949f5c61e8196da71c48655c67bdbbb8d2356 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:23:44 -0800 Subject: [PATCH 0032/1483] Make the animation text keys lower case to help lookup --- apps/openmw/mwrender/animation.cpp | 35 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4b85804676..aedc131890 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -82,6 +82,13 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } } + + NifOgre::TextKeyMap::iterator keyiter; + for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + { + std::transform(keyiter->second.begin(), keyiter->second.end(), + keyiter->second.begin(), ::tolower); + } } } @@ -124,19 +131,12 @@ void Animation::resetPosition(float time) } -struct checklow { - bool operator()(const char &a, const char &b) const - { - return ::tolower(a) == ::tolower(b); - } -}; - 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"; + 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"; NifOgre::TextKeyMap::const_iterator iter; for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) @@ -144,24 +144,20 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim 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(); - std::string::const_iterator strend = iter->second.end(); - size_t strlen = strend-strpos; - - if(start.size() <= strlen && std::mismatch(strpos, strend, start.begin(), checklow()).first == strend) + if(start == iter->second) { times->mStart = iter->first; times->mLoopStart = iter->first; } - else if(startloop.size() <= strlen && std::mismatch(strpos, strend, startloop.begin(), checklow()).first == strend) + else if(startloop == iter->second) { times->mLoopStart = iter->first; } - else if(stoploop.size() <= strlen && std::mismatch(strpos, strend, stoploop.begin(), checklow()).first == strend) + else if(stoploop == iter->second) { times->mLoopStop = iter->first; } - else if(stop.size() <= strlen && std::mismatch(strpos, strend, stop.begin(), checklow()).first == strend) + else if(stop == iter->second) { times->mStop = iter->first; if(times->mLoopStop < 0.0f) @@ -179,6 +175,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) GroupTimes times; times.mLoops = loops; + std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); if(groupname == "all") { times.mStart = times.mLoopStart = 0.0f; From d8dbd5e206c8c028c6d52ee72d498bd5d97c5b49 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:56:03 -0800 Subject: [PATCH 0033/1483] Store text key iterators for the start and stop times --- apps/openmw/mwrender/animation.cpp | 84 +++++++++++++++--------------- apps/openmw/mwrender/animation.hpp | 26 ++++----- 2 files changed, 54 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index aedc131890..b4bfd06841 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,18 +16,16 @@ namespace MWRender Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mInsert(NULL) - , mTime(0.0f) - , mAnimState(NULL) - , mSkipFrame(false) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mStartPosition(0.0f) , mLastPosition(0.0f) + , mTime(0.0f) + , mCurGroup(mTextKeys.end()) + , mNextGroup(mTextKeys.end()) + , mAnimState(NULL) + , mSkipFrame(false) { - mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; - mCurGroup.mLoopStop = mCurGroup.mStop = 0.0f; - mNextGroup.mStart = mNextGroup.mLoopStart = 0.0f; - mNextGroup.mLoopStop = mNextGroup.mStop = 0.0f; } Animation::~Animation() @@ -74,9 +72,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); + mNextGroup = mCurGroup = GroupTimes(mTextKeys.end()); + mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mStartPosition = mNonAccumRoot->getPosition(); mLastPosition = mStartPosition; break; @@ -141,60 +142,57 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim NifOgre::TextKeyMap::const_iterator iter; for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) { - if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f) - return true; - if(start == iter->second) { - times->mStart = iter->first; - times->mLoopStart = iter->first; + times->mStart = iter; + times->mLoopStart = iter; } else if(startloop == iter->second) - { - times->mLoopStart = iter->first; - } + times->mLoopStart = iter; else if(stoploop == iter->second) - { - times->mLoopStop = iter->first; - } + times->mLoopStop = iter; else if(stop == iter->second) { - times->mStop = iter->first; - if(times->mLoopStop < 0.0f) - times->mLoopStop = iter->first; - break; + times->mStop = iter; + if(times->mLoopStop == mTextKeys.end()) + times->mLoopStop = iter; + return (times->mStart != mTextKeys.end()); } } - return (times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f); + return false; } void Animation::playGroup(std::string groupname, int mode, int loops) { - GroupTimes times; + if(mTextKeys.size() == 0) + { + std::cerr<< "Trying to animate an unanimate object" <first; + times.mStart = times.mLoopStart = mTextKeys.begin(); + times.mLoopStop = times.mStop = mTextKeys.end(); } else if(!findGroupTimes(groupname, ×)) - throw std::runtime_error("Failed to find animation group "+groupname); + { + std::cerr<< "Failed to find animation group "< 0) mNextGroup = times; else { mCurGroup = times; - mNextGroup = GroupTimes(); - mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); + mNextGroup = GroupTimes(mTextKeys.end()); + mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; resetPosition(mTime); } } @@ -210,28 +208,28 @@ void Animation::runAnimation(float timepassed) { mTime += timepassed; recheck: - if(mTime >= mCurGroup.mLoopStop) + if(mTime >= mCurGroup.mLoopStop->first) { if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; - updatePosition(mCurGroup.mLoopStop); - mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart; - resetPosition(mCurGroup.mLoopStart); + updatePosition(mCurGroup.mLoopStop->first); + mTime = mTime - mCurGroup.mLoopStop->first + mCurGroup.mLoopStart->first; + resetPosition(mCurGroup.mLoopStart->first); goto recheck; } - else if(mTime >= mCurGroup.mStop) + else if(mTime >= mCurGroup.mStop->first) { if(mNextGroup.mLoops > 0) { - updatePosition(mCurGroup.mStop); - mTime = mTime - mCurGroup.mStop + mNextGroup.mStart; - resetPosition(mNextGroup.mStart); + updatePosition(mCurGroup.mStop->first); + mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; + resetPosition(mNextGroup.mStart->first); mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); + mNextGroup = GroupTimes(mTextKeys.end()); goto recheck; } - mTime = mCurGroup.mStop; + mTime = mCurGroup.mStop->first; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73e34befeb..44a2eaf3ee 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -11,15 +11,15 @@ namespace MWRender class Animation { struct GroupTimes { - float mStart; - float mStop; - float mLoopStart; - float mLoopStop; + NifOgre::TextKeyMap::const_iterator mStart; + NifOgre::TextKeyMap::const_iterator mStop; + NifOgre::TextKeyMap::const_iterator mLoopStart; + NifOgre::TextKeyMap::const_iterator mLoopStop; size_t mLoops; - GroupTimes() - : mStart(-1.0f), mStop(-1.0f), mLoopStart(-1.0f), mLoopStop(-1.0f), + GroupTimes(NifOgre::TextKeyMap::const_iterator iter) + : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), mLoops(0) { } }; @@ -28,13 +28,6 @@ protected: MWWorld::Ptr mPtr; Ogre::SceneNode* mInsert; - float mTime; - GroupTimes mCurGroup; - GroupTimes mNextGroup; - Ogre::AnimationState *mAnimState; - - bool mSkipFrame; - NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; Ogre::Bone *mAccumRoot; @@ -42,6 +35,13 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + float mTime; + GroupTimes mCurGroup; + GroupTimes mNextGroup; + Ogre::AnimationState *mAnimState; + + bool mSkipFrame; + /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ void updatePosition(float time); From 2a9dc5ad94a48353b816f3056ce4c3326e2a7bef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 21:00:21 -0800 Subject: [PATCH 0034/1483] Ensure mCurGroup always has valid iterators, and only get the animation state when animation keys exist --- apps/openmw/mwrender/animation.cpp | 34 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b4bfd06841..6da3ad5836 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -49,17 +49,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); 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(!mAnimState) - mAnimState = state; - } - Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); @@ -72,7 +61,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); - mNextGroup = mCurGroup = GroupTimes(mTextKeys.end()); + mNextGroup = mCurGroup = GroupTimes(mTextKeys.begin()); mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); @@ -84,11 +73,23 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } } - NifOgre::TextKeyMap::iterator keyiter; - for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + if(mTextKeys.size() > 0) { - std::transform(keyiter->second.begin(), keyiter->second.end(), - keyiter->second.begin(), ::tolower); + NifOgre::TextKeyMap::iterator keyiter; + for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + std::transform(keyiter->second.begin(), keyiter->second.end(), + keyiter->second.begin(), ::tolower); + + 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(!mAnimState) + mAnimState = state; + } } } } @@ -179,6 +180,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) { times.mStart = times.mLoopStart = mTextKeys.begin(); times.mLoopStop = times.mStop = mTextKeys.end(); + times.mLoopStop--; times.mStop--; } else if(!findGroupTimes(groupname, ×)) { From d4a9236ae5ef0596dcbf53eaba64948abaa7692e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jan 2013 14:59:40 +0100 Subject: [PATCH 0035/1483] hocking up dialogue sub view to a widget mapper --- apps/opencs/view/world/dialoguesubview.cpp | 52 ++++++++++++++++++++++ apps/opencs/view/world/dialoguesubview.hpp | 3 ++ 2 files changed, 55 insertions(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 354223757d..6138fd3f5e 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -4,6 +4,10 @@ #include #include #include +#include +#include +#include +#include #include "../../model/world/columnbase.hpp" @@ -23,6 +27,9 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM int columns = model->columnCount(); + mWidgetMapper = new QDataWidgetMapper (this); + mWidgetMapper->setModel (model); + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); @@ -30,8 +37,53 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM if (flags & CSMWorld::ColumnBase::Flag_Dialogue) { layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0); + + CSMWorld::ColumnBase::Display display = static_cast + (model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + QWidget *widget = 0; + + if (model->flags (model->index (0, i)) & Qt::ItemIsEditable) + { + switch (display) + { + case CSMWorld::ColumnBase::Display_String: + + layout->addWidget (widget = new QLineEdit, i, 1); + break; + + case CSMWorld::ColumnBase::Display_Integer: + + /// \todo configure widget properly (range) + layout->addWidget (widget = new QSpinBox, i, 1); + break; + + case CSMWorld::ColumnBase::Display_Float: + + /// \todo configure widget properly (range, format?) + layout->addWidget (widget = new QDoubleSpinBox, i, 1); + break; + } + } + else + { + switch (display) + { + case CSMWorld::ColumnBase::Display_String: + case CSMWorld::ColumnBase::Display_Integer: + case CSMWorld::ColumnBase::Display_Float: + + layout->addWidget (widget = new QLabel, i, 1); + break; + } + } + + if (widget) + mWidgetMapper->addMapping (widget, i); } } + + mWidgetMapper->toFirst(); /// \todo use the correct row instead } void CSVWorld::DialogueSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index c57dab1084..64715f5b74 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -3,6 +3,8 @@ #include "../doc/subview.hpp" +class QDataWidgetMapper; + namespace CSMDoc { class Document; @@ -12,6 +14,7 @@ namespace CSVWorld { class DialogueSubView : public CSVDoc::SubView { + QDataWidgetMapper *mWidgetMapper; public: From e44729cd43a98ee35bea3b123f3e021cdc6dceee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 00:17:42 -0800 Subject: [PATCH 0036/1483] Make the text keys lower-case when extracting them I think it's safe to assume all text keys are treated in a case-insensitive manner. So far the only known NiTextKeyExtraData records are for animation keys, which effectively are. --- apps/openmw/mwrender/animation.cpp | 5 ----- components/nifogre/ogre_nif_loader.cpp | 13 +++++++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6da3ad5836..4e33873d32 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -75,11 +75,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(mTextKeys.size() > 0) { - NifOgre::TextKeyMap::iterator keyiter; - for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) - std::transform(keyiter->second.begin(), keyiter->second.end(), - keyiter->second.begin(), ::tolower); - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); while(as.hasMoreElements()) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e71c57efa7..803496bf9e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -286,13 +286,18 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) std::string::size_type pos = 0; while(pos < str.length()) { - while(pos < str.length() && ::isspace(str[pos])) + if(::isspace(str[pos])) + { pos++; - if(pos >= str.length()) - break; + continue; + } std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - textkeys.insert(std::make_pair(tk->list[i].time, str.substr(pos, nextpos-pos))); + std::string result; + result.reserve(str.length()); + std::transform(str.begin()+pos, str.begin()+std::min(str.length(), nextpos), + std::back_inserter(result), ::tolower); + textkeys.insert(std::make_pair(tk->list[i].time, result)); pos = nextpos; } From bb98542c5a5d16c40713e1a0f847d7735a8c7abe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 01:40:38 -0800 Subject: [PATCH 0037/1483] Build separate animations for each group --- apps/openmw/mwrender/animation.cpp | 55 ++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 4 +- components/nifogre/ogre_nif_loader.cpp | 38 ++++++++++++++++++ 3 files changed, 70 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4e33873d32..4448360bd1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,7 +23,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mTime(0.0f) , mCurGroup(mTextKeys.end()) , mNextGroup(mTextKeys.end()) - , mAnimState(NULL) , mSkipFrame(false) { } @@ -80,10 +79,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(as.hasMoreElements()) { Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); + state->setEnabled(false); state->setLoop(false); - if(!mAnimState) - mAnimState = state; } } } @@ -92,12 +89,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model void Animation::updatePosition(float time) { - mAnimState->setTimePosition(time); + mCurGroup.mAnimState->setTimePosition(time); if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; /* Translate the accumulation root back to compensate for the move. */ @@ -118,10 +115,10 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { - mAnimState->setTimePosition(time); + mCurGroup.mAnimState->setTimePosition(time); if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } @@ -162,24 +159,27 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim void Animation::playGroup(std::string groupname, int mode, int loops) { - if(mTextKeys.size() == 0) - { - std::cerr<< "Trying to animate an unanimate object" <getAnimationState(groupname); + times.mLoops = loops; + + if(groupname == "all") + { + times.mStart = times.mLoopStart = mTextKeys.begin(); + times.mLoopStop = times.mStop = mTextKeys.end(); + times.mLoopStop--; times.mStop--; + } + else if(!findGroupTimes(groupname, ×)) + throw std::runtime_error("Failed to find animation group "+groupname); } - else if(!findGroupTimes(groupname, ×)) - { - std::cerr<< "Failed to find animation group "<setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(mTextKeys.end()); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; + mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); } } @@ -201,7 +204,7 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mAnimState && !mSkipFrame) + if(mCurGroup.mAnimState && !mSkipFrame) { mTime += timepassed; recheck: @@ -221,9 +224,11 @@ void Animation::runAnimation(float timepassed) { updatePosition(mCurGroup.mStop->first); mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; - resetPosition(mNextGroup.mStart->first); + mCurGroup.mAnimState->setEnabled(false); mCurGroup = mNextGroup; mNextGroup = GroupTimes(mTextKeys.end()); + mCurGroup.mAnimState->setEnabled(true); + resetPosition(mNextGroup.mStart->first); goto recheck; } mTime = mCurGroup.mStop->first; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 44a2eaf3ee..e84ebb3585 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,11 +16,12 @@ class Animation NifOgre::TextKeyMap::const_iterator mLoopStart; NifOgre::TextKeyMap::const_iterator mLoopStop; + Ogre::AnimationState *mAnimState; size_t mLoops; GroupTimes(NifOgre::TextKeyMap::const_iterator iter) : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), - mLoops(0) + mAnimState(NULL), mLoops(0) { } }; @@ -38,7 +39,6 @@ protected: float mTime; GroupTimes mCurGroup; GroupTimes mNextGroup; - Ogre::AnimationState *mAnimState; bool mSkipFrame; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 803496bf9e..c4846cdfd9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -410,7 +410,45 @@ void loadResource(Ogre::Resource *resource) return; } + TextKeyMap textkeys; + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.peekNext(); + const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(sTextKeyExtraDataID); + if(!data.isEmpty()) + { + textkeys = Ogre::any_cast(data); + break; + } + boneiter.moveNext(); + } + buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); + + std::string currentgroup; + TextKeyMap::const_iterator keyiter = textkeys.begin(); + for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) + { + std::string::size_type sep = keyiter->second.find(':'); + if(sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) + continue; + currentgroup = keyiter->second.substr(0, sep); + + if(skel->hasAnimation(currentgroup)) + continue; + + TextKeyMap::const_reverse_iterator lastkeyiter = textkeys.rbegin(); + while(lastkeyiter->first > keyiter->first) + { + if(lastkeyiter->second.find(':') == currentgroup.length() && + lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) + break; + lastkeyiter++; + } + + buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + } } bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) From 4054934f1699affd865977148f45b4137d8e7b16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 02:51:25 -0800 Subject: [PATCH 0038/1483] Store text keys for each animation --- components/nifogre/ogre_nif_loader.cpp | 29 +++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c4846cdfd9..1b0d3168c1 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -431,23 +431,29 @@ void loadResource(Ogre::Resource *resource) for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) { std::string::size_type sep = keyiter->second.find(':'); - if(sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) + if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || + (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) continue; currentgroup = keyiter->second.substr(0, sep); if(skel->hasAnimation(currentgroup)) continue; - TextKeyMap::const_reverse_iterator lastkeyiter = textkeys.rbegin(); - while(lastkeyiter->first > keyiter->first) + TextKeyMap::const_iterator lastkeyiter = textkeys.end(); + while((--lastkeyiter)->first > keyiter->first) { if(lastkeyiter->second.find(':') == currentgroup.length() && lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) break; - lastkeyiter++; } buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + + TextKeyMap groupkeys; + groupkeys.insert(keyiter, ++lastkeyiter); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); + bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } @@ -459,12 +465,7 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(name); - if(skel.isNull()) - { - NIFSkeletonLoader *loader = &sLoaders[name]; - skel = skelMgr.create(name, group, true, loader); - } + skelMgr.create(name, group, true, &sLoaders[name]); return true; } @@ -1129,8 +1130,12 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam return meshes; } - NIFSkeletonLoader skelldr; - bool hasSkel = skelldr.createSkeleton(name, group, node); + bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); + if(!hasSkel) + { + NIFSkeletonLoader skelldr; + hasSkel = skelldr.createSkeleton(name, group, node); + } NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); From 1e38e381a4344210872ea8f86d5347c1ac5b3fa0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 03:30:55 -0800 Subject: [PATCH 0039/1483] Use text keys for each animation --- apps/openmw/mwrender/animation.cpp | 76 ++++++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 7 ++- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4448360bd1..59dcd451b3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,8 +21,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mTime(0.0f) - , mCurGroup(mTextKeys.end()) - , mNextGroup(mTextKeys.end()) , mSkipFrame(false) { } @@ -48,19 +46,27 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) + { + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); + } + Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); - Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); - while(iter.hasMoreElements()) + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) { - Ogre::Bone *bone = iter.getNext(); + Ogre::Bone *bone = boneiter.peekNext(); const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); if(!data.isEmpty()) { - mTextKeys = Ogre::any_cast(data); - mNextGroup = mCurGroup = GroupTimes(mTextKeys.begin()); + mTextKeys["all"] = Ogre::any_cast(data); mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); @@ -70,17 +76,19 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mLastPosition = mStartPosition; break; } + boneiter.moveNext(); } - if(mTextKeys.size() > 0) + if(boneiter.hasMoreElements()) { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) + asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(false); - state->setLoop(false); + Ogre::AnimationState *state = asiter.getNext(); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+"@"+state->getAnimationName()); + if(!data.isEmpty()) + mTextKeys[state->getAnimationName()] = Ogre::any_cast(data); } } } @@ -127,13 +135,28 @@ void Animation::resetPosition(float time) bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { + const NifOgre::TextKeyMap &textkeys = mTextKeys[groupname]; + if(textkeys.size() == 0) + return false; + + if(groupname == "all") + { + times->mStart = times->mLoopStart = textkeys.begin(); + times->mLoopStop = times->mStop = textkeys.end(); + times->mLoopStop--; times->mStop--; + return true; + } + 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"; + times->mStart = times->mLoopStart = + times->mStop = times->mLoopStop = textkeys.end(); + NifOgre::TextKeyMap::const_iterator iter; - for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) + for(iter = textkeys.begin();iter != textkeys.end();iter++) { if(start == iter->second) { @@ -147,9 +170,9 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim else if(stop == iter->second) { times->mStop = iter; - if(times->mLoopStop == mTextKeys.end()) + if(times->mLoopStop == textkeys.end()) times->mLoopStop = iter; - return (times->mStart != mTextKeys.end()); + return (times->mStart != textkeys.end()); } } @@ -159,23 +182,14 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim void Animation::playGroup(std::string groupname, int mode, int loops) { - GroupTimes times(mTextKeys.end()); + GroupTimes times; try { - if(mTextKeys.size() == 0) - throw std::runtime_error("Trying to animate an unanimate object"); - std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); times.mLoops = loops; - if(groupname == "all") - { - times.mStart = times.mLoopStart = mTextKeys.begin(); - times.mLoopStop = times.mStop = mTextKeys.end(); - times.mLoopStop--; times.mStop--; - } - else if(!findGroupTimes(groupname, ×)) + if(!findGroupTimes(groupname, ×)) throw std::runtime_error("Failed to find animation group "+groupname); } catch(std::exception &e) { @@ -190,7 +204,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) if(mCurGroup.mAnimState) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; - mNextGroup = GroupTimes(mTextKeys.end()); + mNextGroup = GroupTimes(); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); @@ -226,9 +240,9 @@ void Animation::runAnimation(float timepassed) mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; mCurGroup.mAnimState->setEnabled(false); mCurGroup = mNextGroup; - mNextGroup = GroupTimes(mTextKeys.end()); + mNextGroup = GroupTimes(); mCurGroup.mAnimState->setEnabled(true); - resetPosition(mNextGroup.mStart->first); + resetPosition(mCurGroup.mStart->first); goto recheck; } mTime = mCurGroup.mStop->first; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e84ebb3585..859d2b9893 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -19,9 +19,8 @@ class Animation Ogre::AnimationState *mAnimState; size_t mLoops; - GroupTimes(NifOgre::TextKeyMap::const_iterator iter) - : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), - mAnimState(NULL), mLoops(0) + GroupTimes() + : mAnimState(NULL), mLoops(0) { } }; @@ -30,7 +29,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; - NifOgre::TextKeyMap mTextKeys; + std::map mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mStartPosition; From 465fd9c8afbce80590fd8b48d244cd6bbd344e52 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 04:10:02 -0800 Subject: [PATCH 0040/1483] Offset animation times to start at 0 --- components/nifogre/ogre_nif_loader.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1b0d3168c1..b065e5fd35 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -164,7 +164,7 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { - Ogre::Animation *anim = skel->createAnimation(name, stopTime); + Ogre::Animation *anim = skel->createAnimation(name, stopTime-startTime); for(size_t i = 0;i < ctrls.size();i++) { @@ -246,7 +246,7 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const } Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); + kframe = nodetrack->createNodeKeyFrame(curtime-startTime); if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) kframe->setRotation(curquat); else @@ -450,8 +450,12 @@ void loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + TextKeyMap::const_iterator insiter = keyiter; TextKeyMap groupkeys; - groupkeys.insert(keyiter, ++lastkeyiter); + do { + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); + } while(insiter++ != lastkeyiter); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } From 015bb0bf1f309fcff7b61a4e23cdb8484fb97c45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 04:30:32 -0800 Subject: [PATCH 0041/1483] Use the calculated max time for the "all" 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 b065e5fd35..b37b989c7f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -424,7 +424,7 @@ void loadResource(Ogre::Resource *resource) boneiter.moveNext(); } - buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); + buildAnimation(skel, "all", ctrls, targets, 0.0f, maxtime); std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); From a9bcbfd8d364210c75120e36f258792d45e90edd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 05:11:32 -0800 Subject: [PATCH 0042/1483] Use Node::_getFullTransform instead of building the matrix manually --- components/nifogre/ogre_nif_loader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b37b989c7f..08a5855ed0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -803,12 +803,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader for(size_t b = 0;b < bones.length();b++) { Ogre::Bone *bone = skel->getBone(bones[b]->name); - Ogre::Matrix4 mat, mat2; + Ogre::Matrix4 mat; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat2.makeTransform(bone->_getDerivedPosition(), bone->_getDerivedScale(), - bone->_getDerivedOrientation()); - mat = mat2 * mat; + mat = bone->_getFullTransform() * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) From 4b7cc1372f4d2500effee6fb3482a1e8fc56b9f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 06:32:31 -0800 Subject: [PATCH 0043/1483] Some cleanup --- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 08a5855ed0..cfc0d8397f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1008,7 +1008,7 @@ public: virtual void loadResource(Ogre::Resource *resource) { Ogre::Mesh *mesh = dynamic_cast(resource); - assert(mesh && "Attempting to load a mesh into a non-mesh resource!"); + OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); if(!mShapeName.length()) { @@ -1116,7 +1116,7 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam Nif::NIFFile nif(name); if (nif.numRecords() < 1) { - nif.warn("Found no records in NIF."); + nif.warn("Found no NIF records in "+name+"."); return meshes; } @@ -1127,8 +1127,8 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam 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."); + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); return meshes; } @@ -1204,16 +1204,13 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = bonename; - std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower); + std::string filter; filter.resize(bonename.length()); + std::transform(bonename.begin(), bonename.end(), filter.begin(), ::tolower); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - std::transform(meshes[i].mTargetNode.begin(), meshes[i].mTargetNode.end(), - meshes[i].mTargetNode.begin(), ::tolower); - if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) { sceneMgr->destroyEntity(ent); From 625a538f03e9d88adbd3431bb7c8810bc3d6c564 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 07:43:10 -0800 Subject: [PATCH 0044/1483] Combine part selection into a single loop --- apps/openmw/mwrender/npcanimation.cpp | 239 +++++++++++--------------- 1 file changed, 96 insertions(+), 143 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5682a86cc9..e4eea6c710 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -133,161 +133,114 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor void NpcAnimation::updateParts() { - bool apparelChanged = false; - static const struct { - MWWorld::ContainerStoreIterator NpcAnimation::*iter; + int numRemoveParts; // Max: 1 + ESM::PartReferenceType removeParts[1]; + + MWWorld::ContainerStoreIterator NpcAnimation::*part; int slot; + + int numReserveParts; // Max: 12 + ESM::PartReferenceType reserveParts[12]; } slotlist[] = { - { &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe }, - { &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, - { &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet }, - { &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, - { &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves }, - { &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, - { &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, - { &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots }, - { &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, - { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, - { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt }, - { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants }, + { 0, { }, + &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe, + 12, { ESM::PRT_Groin, ESM::PRT_Skirt, ESM::PRT_RLeg, ESM::PRT_LLeg, + ESM::PRT_RUpperarm, ESM::PRT_LUpperarm, ESM::PRT_RKnee, ESM::PRT_LKnee, + ESM::PRT_RForearm, ESM::PRT_LForearm, ESM::PRT_RPauldron, ESM::PRT_LPauldron } + }, + + { 0, { }, + &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt, + 3, { ESM::PRT_Groin, ESM::PRT_RLeg, ESM::PRT_LLeg } + }, + + { 1, { ESM::PRT_Hair }, + &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, + 0, { } + }, }; - for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) + static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + + for(size_t i = 0;i < slotlistsize;i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(this->*slotlist[i].iter != iter) - { - this->*slotlist[i].iter = iter; - removePartGroup(slotlist[i].slot); - apparelChanged = true; - } - } + if(this->*slotlist[i].part == iter) + continue; - if(apparelChanged) - { - if(mRobe != mInv.end()) - { - MWWorld::Ptr ptr = *mRobe; + this->*slotlist[i].part = iter; + removePartGroup(slotlist[i].slot); - const ESM::Clothing *clothes = (ptr.get())->mBase; + if(this->*slotlist[i].part == mInv.end()) + continue; + + for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++) + removeIndividualPart(slotlist[i].removeParts[rem]); + + int prio = 1; + MWWorld::ContainerStoreIterator &store = this->*slotlist[i].part; + if(store->getTypeName() == typeid(ESM::Clothing).name()) + { + prio = ((slotlist[i].numReserveParts+1)<<1) + 0; + const ESM::Clothing *clothes = store->get()->mBase; std::vector parts = clothes->mParts.mParts; - 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(slotlist[i].slot, prio, parts); } - if(mSkirtIter != mInv.end()) + else if(store->getTypeName() == typeid(ESM::Armor).name()) { - MWWorld::Ptr ptr = *mSkirtIter; - - const ESM::Clothing *clothes = (ptr.get())->mBase; - std::vector parts = clothes->mParts.mParts; - 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); + prio = ((slotlist[i].numReserveParts+1)<<1) + 1; + const ESM::Armor *armor = store->get()->mBase; + std::vector parts = armor->mParts.mParts; + addPartGroup(slotlist[i].slot, prio, parts); } - if(mHelmet != mInv.end()) - { - removeIndividualPart(ESM::PRT_Hair); - const ESM::Armor *armor = (mHelmet->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); - } - if(mCuirass != mInv.end()) - { - const ESM::Armor *armor = (mCuirass->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); - } - if(mGreaves != mInv.end()) - { - const ESM::Armor *armor = (mGreaves->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); - } - - if(mPauldronL != mInv.end()) - { - const ESM::Armor *armor = (mPauldronL->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); - } - if(mPauldronR != mInv.end()) - { - const ESM::Armor *armor = (mPauldronR->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); - } - if(mBoots != mInv.end()) - { - if(mBoots->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mBoots->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); - } - else if(mBoots->getTypeName() == typeid(ESM::Armor).name()) - { - const ESM::Armor *armor = (mBoots->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); - } - } - if(mGloveL != mInv.end()) - { - if(mGloveL->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mGloveL->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (mGloveL->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); - } - } - if(mGloveR != mInv.end()) - { - if(mGloveR->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mGloveR->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (mGloveR->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); - } - - } - - if(mShirt != mInv.end()) - { - const ESM::Clothing *clothes = (mShirt->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); - } - if(mPants != mInv.end()) - { - const ESM::Clothing *clothes = (mPants->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); - } + for(int res = 0;res < slotlist[i].numReserveParts;res++) + reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio); } if(mPartPriorities[ESM::PRT_Head] < 1) @@ -455,7 +408,7 @@ void NpcAnimation::addPartGroup(int group, int priority, std::vectormModel); + addOrReplaceIndividualPart(part.mPart, group, priority, "meshes\\"+bodypart->mModel); else reserveIndividualPart(part.mPart, group, priority); } From 9fedaf18d6d724156910e23be9325882c79787a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 07:55:55 -0800 Subject: [PATCH 0045/1483] Make some methods private --- apps/openmw/mwrender/npcanimation.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 090366a234..1a121be073 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -83,12 +83,7 @@ private: int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[sPartListSize]; -public: - NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& inv, int visibilityFlags); - virtual ~NpcAnimation(); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); - virtual void runAnimation(float timepassed); void updateParts(); void removeEntities(NifOgre::EntityList &entities); void removeIndividualPart(int type); @@ -98,6 +93,13 @@ public: void removePartGroup(int group); void addPartGroup(int group, int priority, std::vector& parts); +public: + NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, + MWWorld::InventoryStore& inv, int visibilityFlags); + virtual ~NpcAnimation(); + + virtual void runAnimation(float timepassed); + void forceUpdate(); }; From be74859f05257b0cbf3ba8884b39df8570a2d14d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 08:03:28 -0800 Subject: [PATCH 0046/1483] Avoid some unnecessary copying when calling addPartGroup --- apps/openmw/mwrender/npcanimation.cpp | 10 ++++------ apps/openmw/mwrender/npcanimation.hpp | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e4eea6c710..4fddb20205 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -228,15 +228,13 @@ void NpcAnimation::updateParts() { prio = ((slotlist[i].numReserveParts+1)<<1) + 0; const ESM::Clothing *clothes = store->get()->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(slotlist[i].slot, prio, parts); + addPartGroup(slotlist[i].slot, prio, clothes->mParts.mParts); } else if(store->getTypeName() == typeid(ESM::Armor).name()) { prio = ((slotlist[i].numReserveParts+1)<<1) + 1; const ESM::Armor *armor = store->get()->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(slotlist[i].slot, prio, parts); + addPartGroup(slotlist[i].slot, prio, armor->mParts.mParts); } for(int res = 0;res < slotlist[i].numReserveParts;res++) @@ -392,11 +390,11 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, return true; } -void NpcAnimation::addPartGroup(int group, int priority, std::vector &parts) +void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts) { for(std::size_t i = 0; i < parts.size(); i++) { - ESM::PartReference &part = parts[i]; + const ESM::PartReference &part = parts[i]; const MWWorld::Store &partStore = MWBase::Environment::get().getWorld()->getStore().get(); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1a121be073..1610913176 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -91,7 +91,7 @@ private: bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); void removePartGroup(int group); - void addPartGroup(int group, int priority, std::vector& parts); + void addPartGroup(int group, int priority, const std::vector &parts); public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, From c4c8295e0b0144adc8ba3f1f77b55594c553bbe0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 09:10:59 -0800 Subject: [PATCH 0047/1483] Rename NIFLoader to Loader, and update some comments --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 6 ++---- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 6 +++--- components/nifogre/ogre_nif_loader.cpp | 22 +++++++++++++++------- components/nifogre/ogre_nif_loader.hpp | 23 +++-------------------- 6 files changed, 25 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 59dcd451b3..b8016d0872 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -43,7 +43,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mInsert = node; assert(mInsert); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); + mEntityList = NifOgre::Loader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4fddb20205..ab4c7fa7cc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -11,8 +11,6 @@ #include "renderconst.hpp" -using namespace Ogre; -using namespace NifOgre; namespace MWRender { @@ -299,8 +297,8 @@ void NpcAnimation::updateParts() NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename) { - NifOgre::EntityList entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename, - mInsert, mesh); + NifOgre::EntityList entities = NifOgre::Loader::createEntities(mEntityList.mSkelBase, bonename, + mInsert, mesh); std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4c3b1166b3..d0087e8dc6 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::Loader::createEntities(insert, 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 c8a6ca0eff..0602fc8bb7 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -324,7 +324,7 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); + NifOgre::EntityList entities = NifOgre::Loader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { Entity* night1_ent = entities.mEntities[i]; @@ -349,7 +349,7 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); + entities = NifOgre::Loader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* atmosphere_ent = entities.mEntities[i]; @@ -363,7 +363,7 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); + entities = NifOgre::Loader::createEntities(clouds_node, "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 cfc0d8397f..f078d90c9f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -148,8 +148,12 @@ public: }; -class NIFSkeletonLoader : public Ogre::ManualResourceLoader { - +/** Manual resource loader for NIF skeletons. This is the main class + responsible for translating the internal NIF skeleton structure into + something Ogre can use (includes animations and node TextKeyData). + */ +class NIFSkeletonLoader : public Ogre::ManualResourceLoader +{ static void warn(const std::string &msg) { std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; @@ -754,6 +758,10 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String std::map NIFMaterialLoader::MaterialMap; +/** Manual resource loader for NIF meshes. This is the main class + responsible for translating the internal NIF mesh structure into + something Ogre can use. + */ class NIFMeshLoader : Ogre::ManualResourceLoader { std::string mName; @@ -1106,7 +1114,7 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshInfoMap; static MeshInfoMap sMeshInfoMap; -MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList Loader::load(const std::string &name, const std::string &skelName, const std::string &group) { MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); if(meshiter != sMeshInfoMap.end()) @@ -1145,7 +1153,7 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) +EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; @@ -1192,9 +1200,9 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na return entitylist; } -EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, const std::string &group) +EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, const std::string &group) { EntityList entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 4ed52a84a7..f87d7d3c21 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -31,17 +31,12 @@ #include #include -namespace Nif -{ - class Node; - class Transformation; - class NiTriShape; -} +// FIXME: This namespace really doesn't do anything Nif-specific. Any supportable +// model format should go through this. namespace NifOgre { -// FIXME: These should not be in NifOgre, it works agnostic of what model format is used typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { @@ -69,19 +64,7 @@ struct MeshInfo { }; typedef std::vector MeshInfoList; -/** Manual resource loader for NIF meshes. This is the main class - responsible for translating the internal NIF mesh structure into - something Ogre can use. - - You have to insert meshes manually into Ogre like this: - - NIFLoader::load("somemesh.nif"); - - 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 +class Loader { static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); From bc73c5b1ecaa8001bdeeac46864d4e22026b104a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 20:08:59 +0100 Subject: [PATCH 0048/1483] enable directional lighting for character previews --- apps/openmw/mwrender/characterpreview.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b034e098bc..a172d02b1c 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -39,6 +39,15 @@ namespace MWRender void CharacterPreview::setup () { mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); + + /// \todo Read the fallback values from INIImporter (Inventory:Directional*) + Ogre::Light* l = mSceneMgr->createLight(); + l->setType (Ogre::Light::LT_DIRECTIONAL); + l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + l->setDiffuseColour (Ogre::ColourValue(1,1,1)); + + mSceneMgr->setAmbientLight (Ogre::ColourValue(0.5, 0.5, 0.5)); + mCamera = mSceneMgr->createCamera (mName); mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); @@ -72,7 +81,6 @@ namespace MWRender mViewport->setOverlaysEnabled(false); mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); mViewport->setShadowsEnabled(false); - mViewport->setMaterialScheme("local_map"); mViewport->setVisibilityMask (RV_PlayerPreview); mRenderTarget->setActive(true); mRenderTarget->setAutoUpdated (false); From 111e38ef25546836d243c9b14c72bd055478a53b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 20:18:26 +0100 Subject: [PATCH 0049/1483] Revert "fog now distance based instead of depth" This reverts commit 7ee038fdd7fcb51f901893ae0e6554a2f0cc3dc1. --- files/materials/objects.shader | 2 +- files/materials/openmw.configuration | 1 + files/materials/terrain.shader | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 25624351c8..130de0f3d6 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -265,7 +265,7 @@ #endif #if FOG - float fogValue = shSaturate((length(cameraPos.xyz-worldPos) - fogParams.y) * fogParams.w); + float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); #if UNDERWATER // regular fog only if fragment is above water diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index 2f84680f0e..ee97451d39 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -1,5 +1,6 @@ configuration water_reflection { + fog false shadows false shadows_pssm false mrt_output false diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index dee7332630..9494c1de99 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -337,7 +337,7 @@ #if FOG - float fogValue = shSaturate((length(cameraPos.xyz-worldPos) - fogParams.y) * fogParams.w); + float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); #if UNDERWATER // regular fog only if fragment is above water From bd8d793fec20fe751651abfcebd7ef0704ffbb8b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 21:41:40 +0100 Subject: [PATCH 0050/1483] Removing gamma correction due to caused inconsistencies. --- files/materials/core.h | 7 ++++--- files/materials/objects.shader | 2 +- files/materials/terrain.shader | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/files/materials/core.h b/files/materials/core.h index 1c9ea1d1d2..0e46369efd 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -1,7 +1,8 @@ -#define gammaCorrectRead(v) pow(max(v, 0.00001f), float3(gammaCorrection,gammaCorrection,gammaCorrection)) -#define gammaCorrectOutput(v) pow(max(v, 0.00001f), float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) - +//#define gammaCorrectRead(v) pow(max(v, 0.00001f), float3(gammaCorrection,gammaCorrection,gammaCorrection)) +//#define gammaCorrectOutput(v) pow(max(v, 0.00001f), float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) +#define gammaCorrectRead(v) v +#define gammaCorrectOutput(v) v #if SH_HLSL == 1 || SH_CG == 1 diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 130de0f3d6..c68705c42e 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -112,7 +112,7 @@ shUniform(float, far) @shAutoConstant(far, far_clip_distance) #endif - shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) + //shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) #if LIGHTING shInput(float3, normalPassthrough) diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 9494c1de99..dfe998210e 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -137,7 +137,7 @@ shSampler2D(normalMap) // global normal map - shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) + //shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) @shForeach(@shPropertyString(num_blendmaps)) From b8c6f6640b9f01c0f7925f33819e1da73b34c509 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 21:56:26 +0100 Subject: [PATCH 0051/1483] Fixing water <-> waterfall blending issues (Sort of... the second part will follow later) --- apps/openmw/mwrender/water.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e8f099640b..80fe547074 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -48,7 +48,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); - mWater->setRenderQueueGroup(RQG_Water); mWater->setCastShadows(false); mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); @@ -324,7 +323,11 @@ void Water::applyRTT() mReflectionTarget = rtt; sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mReflectionTexture->getName()); + + mWater->setRenderQueueGroup(RQG_Water); } + else + mWater->setRenderQueueGroup(RQG_Alpha); } void Water::applyVisibilityMask() From d3c0851aa72cb47b977cf6377ae03c73a2859335 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 22:08:42 +0100 Subject: [PATCH 0052/1483] Changed light attenuation back to linear in all cases, this seems to be what MW does. --- apps/openmw/mwrender/objects.cpp | 7 +++---- apps/openmw/mwrender/water.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index ee36126f8d..810d7af419 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -238,17 +238,16 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f info.time = Ogre::Math::RangeRandom(-500, +500); info.phase = Ogre::Math::RangeRandom(-500, +500); - // adjust the lights depending if we're in an interior or exterior cell - // quadratic means the light intensity falls off quite fast, resulting in a - // dark, atmospheric environment (perfect for exteriors) - // for interiors, we want more "warm" lights, so use linear attenuation. + // changed to linear to look like morrowind bool quadratic = false; + /* if (!lightOutQuadInLin) quadratic = lightQuadratic; else { quadratic = !info.interior; } + */ if (!quadratic) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 80fe547074..a16a23b26c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -315,7 +315,7 @@ void Water::applyRTT() vp->setOverlaysEnabled(false); vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setShadowsEnabled(false); - // use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain) + // use fallback techniques without shadows and without mrt vp->setMaterialScheme("water_reflection"); rtt->addListener(this); rtt->setActive(true); From 455ec0996df77bea43903741b37eda7b57aecb51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 22:27:58 +0100 Subject: [PATCH 0053/1483] Shaders & textures are now loaded upon loading the NIF, instead of when the object becomes visible in the camera frustum. Should improve responsiveness. --- components/nifogre/ogre_nif_loader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 31d873489c..35060e50b7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -656,6 +656,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String else instance->getMaterial ()->setShadowCasterMaterial ("openmw_shadowcaster_noalpha"); + sh::Factory::getInstance ()._ensureMaterial (matname, "Default"); + // As of yet UNTESTED code from Chris: /*pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); From 35015ef11002547835851979ad6ffd9e48487ceb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 23:11:15 +0100 Subject: [PATCH 0054/1483] Change default settings to use no object shaders and per vertex lighting, as some lights in MW look clearly broken with per pixel lighting enabled (e.g. fireplace in census office, ghostfence) --- files/settings-default.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 1768b2f5ec..26546c2b15 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -96,7 +96,7 @@ fps = 0 crosshair = true [Objects] -shaders = true +shaders = false # Max. number of lights that affect objects. Setting to 1 will only reflect sunlight # Note: has no effect when shaders are turned off @@ -132,7 +132,7 @@ num lights = 8 # Enable this to get fancy-looking water with reflections and refractions # Only available if object shaders are on # All the settings below have no effect if this is false -shader = true +shader = false rtt size = 512 reflect terrain = true @@ -142,7 +142,7 @@ reflect actors = false reflect misc = false # Enable underwater effect. It is not resource intensive, so only disable it if you have problems. -underwater effect = true +underwater effect = false [Sound] # Device name. Blank means default From 55769aaf911cb06ffa856d5a9d14a77c5f4b3ada Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 Jan 2013 01:46:00 +0100 Subject: [PATCH 0055/1483] Fix selection buffer (i.e. item selection on the inventory character preview) when object shaders were disabled --- apps/openmw/engine.cpp | 4 +--- files/materials/selection.mat | 1 + files/materials/water.mat | 2 +- files/materials/water.shader | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8c288a2ee2..31eb68fa75 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -391,8 +391,6 @@ void OMW::Engine::go() MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos); } - std::cout << "\nPress Q/ESC or close window to exit.\n"; - mOgre->getRoot()->addFrameListener (this); // Play some good 'ol tunes @@ -420,7 +418,7 @@ void OMW::Engine::go() // Save user settings settings.saveUser(settingspath); - std::cout << "Quitting peacefully.\n"; + std::cout << "Quitting peacefully." << std::endl; } void OMW::Engine::activate() diff --git a/files/materials/selection.mat b/files/materials/selection.mat index a76dd71792..2cb92f8843 100644 --- a/files/materials/selection.mat +++ b/files/materials/selection.mat @@ -1,5 +1,6 @@ material SelectionColour { + allow_fixed_function false pass { vertex_program selection_vertex diff --git a/files/materials/water.mat b/files/materials/water.mat index dcea5a0d07..a5f9f2ec9e 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -2,7 +2,7 @@ material Water { pass { - emissive 0.6 0.7 1.0 + emissive 1.0 1.0 1.0 ambient 0 0 0 diffuse 0 0 0 1 specular 0 0 0 32 diff --git a/files/materials/water.shader b/files/materials/water.shader index 6bd277eab6..9ebea0f002 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -42,7 +42,7 @@ SH_START_PROGRAM { - shOutputColour(0).xyz = shSample(animatedTexture, UV * 15).xyz * float3(0.6, 0.7, 1.0); + shOutputColour(0).xyz = shSample(animatedTexture, UV * 15).xyz * float3(1.0, 1.0, 1.0); shOutputColour(0).w = 0.7; float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); From 7f2d71554eea9067e3077534e17f04817f0ed47c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 04:16:18 -0800 Subject: [PATCH 0056/1483] Use the correct offset when building static geometry from an entity --- apps/openmw/mwrender/objects.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index d0087e8dc6..bd5f95c240 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -193,13 +193,15 @@ 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.mEntities.size();i++) + std::vector::reverse_iterator iter = entities.mEntities.rbegin(); + while(iter != entities.mEntities.rend()) { - Ogre::Entity *ent = entities.mEntities[i]; - insert->detachObject(ent); - sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); + Ogre::Node *node = (*iter)->getParentNode(); + sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); - mRenderer.getScene()->destroyEntity(ent); + (*iter)->detachFromParent(); + mRenderer.getScene()->destroyEntity(*iter); + iter++; } } } From e8ac3976b58e9d93cb5f8fe9c78aae391d88e05a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 06:35:06 -0800 Subject: [PATCH 0057/1483] Fix some subentity assumptions --- apps/openmw/mwrender/sky.cpp | 74 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0602fc8bb7..3592eb46e9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -205,44 +205,48 @@ unsigned int Moon::getPhaseInt() const void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) { - // Get the vertex colour buffer of this mesh - const Ogre::VertexElement* ves_diffuse = ent->getMesh()->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE ); - HardwareVertexBufferSharedPtr colourBuffer = ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource()); - - // Lock - void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL); - - // Iterate over all vertices - int vertex_size = colourBuffer->getVertexSize(); - float * currentVertex = NULL; - for (unsigned int i=0; igetNumVertices(); ++i) + for(unsigned int idx = 0;idx < ent->getNumSubEntities();idx++) { - // Get a pointer to the vertex colour - ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex ); + Ogre::SubMesh *submesh = ent->getSubEntity(idx)->getSubMesh(); + // Get the vertex colour buffer of this mesh + const Ogre::VertexElement* ves_diffuse = submesh->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE ); + HardwareVertexBufferSharedPtr colourBuffer = submesh->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource()); - unsigned char alpha=0; - if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row - else if (meshType == 1) + // Lock + void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL); + + // Iterate over all vertices + int vertex_size = colourBuffer->getVertexSize(); + for (unsigned int i=0; igetNumVertices(); ++i) { - if (i>= 49 && i <= 64) alpha = 0; // bottom-most row - else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row - else alpha = 255; + // Get a pointer to the vertex colour + float *currentVertex = NULL; + ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex ); + + unsigned char alpha=0; + if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (meshType == 1) + { + if (i>= 49 && i <= 64) alpha = 0; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row + else alpha = 255; + } + // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 + uint8 tmpR = static_cast(255); + uint8 tmpG = static_cast(255); + uint8 tmpB = static_cast(255); + uint8 tmpA = static_cast(alpha); + + // Modify + *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); + + // Move to the next vertex + pData = static_cast (pData) + vertex_size; } - // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 - uint8 tmpR = static_cast(255); - uint8 tmpG = static_cast(255); - uint8 tmpB = static_cast(255); - uint8 tmpA = static_cast(alpha); - // Modify - *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); - - // Move to the next vertex - pData = static_cast (pData) + vertex_size; + // Unlock + colourBuffer->unlock(); } - - // Unlock - ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock(); } SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) @@ -356,7 +360,8 @@ void SkyManager::create() atmosphere_ent->setCastShadows(false); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); - atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); + for(unsigned int j = 0;j < atmosphere_ent->getNumSubEntities();j++) + atmosphere_ent->getSubEntity (j)->setMaterialName("openmw_atmosphere"); ModVertexAlpha(atmosphere_ent, 0); } @@ -369,7 +374,8 @@ void SkyManager::create() Entity* clouds_ent = entities.mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); + for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) + clouds_ent->getSubEntity(j)->setMaterialName("openmw_clouds"); clouds_ent->setCastShadows(false); ModVertexAlpha(clouds_ent, 1); From 771a5f73166d53c219cfe35763d487cda62be1df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 08:35:24 -0800 Subject: [PATCH 0058/1483] Add the beginnings of a character controller --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/character.cpp | 26 ++++++++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 9 +++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwmechanics/character.cpp create mode 100644 apps/openmw/mwmechanics/character.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090c..563c9e422a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,7 +62,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells + mechanicsmanagerimp stat character creaturestats magiceffects movement actors drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate ) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp new file mode 100644 index 0000000000..319c4fe9bd --- /dev/null +++ b/apps/openmw/mwmechanics/character.cpp @@ -0,0 +1,26 @@ +/* + * OpenMW - The completely unofficial reimplementation of Morrowind + * + * This file (character.cpp) is part of the OpenMW package. + * + * OpenMW is distributed as free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * version 3, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 3 along with this program. If not, see + * http://www.gnu.org/licenses/ . + */ + +#include "character.hpp" + + +namespace MWMechanics +{ + +} diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp new file mode 100644 index 0000000000..cab269112e --- /dev/null +++ b/apps/openmw/mwmechanics/character.hpp @@ -0,0 +1,9 @@ +#ifndef GAME_MWMECHANICS_CHARACTER_HPP +#define GAME_MWMECHANICS_CHARACTER_HPP + +namespace MWMechanics +{ + +} + +#endif /* GAME_MWMECHANICS_CHARACTER_HPP */ From 97f8c73d91a01f9682539aa0cee44b08f585caeb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 11:09:33 -0800 Subject: [PATCH 0059/1483] Remove some useless parameters SceneNode::setVisibility merely passes the value to its attached object, of which there are none at the point it would be called. Additionally, the method is always called with enabled=true anyway. --- apps/openmw/mwrender/actors.cpp | 33 +++++++++++++++------------------ apps/openmw/mwrender/actors.hpp | 2 +- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index fc5a46d12b..ec7c9d0732 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -27,14 +27,9 @@ Actors::~Actors(){ void Actors::setMwRoot(Ogre::SceneNode* root){ mMwRoot = root; } -void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){ - insertBegin(ptr, true, true); - NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors); - - mAllActors[ptr] = anim; -} -void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ +void Actors::insertBegin (const MWWorld::Ptr& ptr) +{ Ogre::SceneNode* cellnode; if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) { @@ -66,26 +61,28 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ // Rotates first around z, then y, then x insert->setOrientation(xr*yr*zr); - if (!enabled) - insert->setVisible (false); ptr.getRefData().setBaseNode(insert); - - } -void Actors::insertCreature (const MWWorld::Ptr& ptr){ - insertBegin(ptr, true, true); - CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr); - //mAllActors.insert(std::pair(ptr,anim)); +void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv) +{ + insertBegin(ptr); + NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), inv, RV_Actors); + delete mAllActors[ptr]; + mAllActors[ptr] = anim; +} +void Actors::insertCreature (const MWWorld::Ptr& ptr) +{ + insertBegin(ptr); + CreatureAnimation* anim = new CreatureAnimation(ptr); delete mAllActors[ptr]; mAllActors[ptr] = anim; - //mAllActors.push_back(&anim);*/ } bool Actors::deleteObject (const MWWorld::Ptr& ptr) { - delete mAllActors[ptr]; - mAllActors.erase(ptr); + delete mAllActors[ptr]; + mAllActors.erase(ptr); if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode()) { diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 71be0bd7b7..6ea6a81377 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -25,7 +25,7 @@ namespace MWRender Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); void setMwRoot(Ogre::SceneNode* root); - void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); + void insertBegin (const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); bool deleteObject (const MWWorld::Ptr& ptr); From 30136eb4496b4e81e62548825ef468906db32029 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jan 2013 06:36:48 +0100 Subject: [PATCH 0060/1483] Update settings UI --- apps/openmw/mwgui/settingswindow.cpp | 60 +++++++++-------------- apps/openmw/mwgui/settingswindow.hpp | 3 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 7 +-- files/mygui/openmw_settings_window.layout | 40 ++++++--------- files/settings-default.cfg | 2 - 6 files changed, 43 insertions(+), 73 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index cdfe4d2b68..294921cdd0 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -109,6 +109,7 @@ namespace MWGui getWidget(mReflectActorsButton, "ReflectActorsButton"); getWidget(mReflectTerrainButton, "ReflectTerrainButton"); getWidget(mShadersButton, "ShadersButton"); + getWidget(mShaderModeButton, "ShaderModeButton"); getWidget(mShadowsEnabledButton, "ShadowsEnabledButton"); getWidget(mShadowsLargeDistance, "ShadowsLargeDistance"); getWidget(mShadowsTextureSize, "ShadowsTextureSize"); @@ -122,7 +123,6 @@ namespace MWGui getWidget(mInvertYButton, "InvertYButton"); getWidget(mUISensitivitySlider, "UISensitivitySlider"); getWidget(mCameraSensitivitySlider, "CameraSensitivitySlider"); - getWidget(mGammaSlider, "GammaSlider"); mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -130,6 +130,7 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mUnderwaterButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mShadersButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadersToggled); + mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mWaterShaderButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectObjectsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -144,7 +145,6 @@ namespace MWGui mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mAnisotropySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mGammaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mShadowsEnabledButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mShadowsLargeDistance->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -202,14 +202,6 @@ namespace MWGui getWidget(fovText, "FovText"); fovText->setCaption("Field of View (" + boost::lexical_cast(int(Settings::Manager::getFloat("field of view", "General"))) + ")"); - float gammaVal = (Settings::Manager::getFloat("gamma", "Video")-0.1f)/(3.f-0.1f); - mGammaSlider->setScrollPosition(gammaVal * (mGammaSlider->getScrollRange()-1)); - MyGUI::TextBox* gammaText; - getWidget(gammaText, "GammaText"); - std::stringstream gamma; - gamma << std::setprecision (2) << Settings::Manager::getFloat("gamma", "Video"); - gammaText->setCaption("Gamma (" + gamma.str() + ")"); - float anisotropyVal = Settings::Manager::getInt("anisotropy", "General") / 16.0; mAnisotropySlider->setScrollPosition(anisotropyVal * (mAnisotropySlider->getScrollRange()-1)); std::string tf = Settings::Manager::getString("texture filtering", "General"); @@ -250,14 +242,8 @@ namespace MWGui mInvertYButton->setCaptionWithReplacing(Settings::Manager::getBool("invert y axis", "Input") ? "#{sOn}" : "#{sOff}"); - std::string shaders; - if (!Settings::Manager::getBool("shaders", "Objects")) - shaders = "off"; - else - { - shaders = Settings::Manager::getString("shader mode", "General"); - } - mShadersButton->setCaption (shaders); + mShadersButton->setCaption (Settings::Manager::getBool("shaders", "Objects") ? "on" : "off"); + mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); if (!MWRender::RenderingManager::waterShaderSupported()) { @@ -267,7 +253,7 @@ namespace MWGui mReflectTerrainButton->setEnabled(false); } - if (shaders == "off") + if (!Settings::Manager::getBool("shaders", "Objects")) { mUnderwaterButton->setEnabled (false); mShadowsEnabledButton->setEnabled(false); @@ -424,19 +410,31 @@ namespace MWGui } } + void SettingsWindow::onShaderModeToggled(MyGUI::Widget* _sender) + { + std::string val = static_cast(_sender)->getCaption(); + if (val == "cg") + { + val = hlslGlsl(); + } + else + val = "cg"; + + static_cast(_sender)->setCaption(val); + + Settings::Manager::setString("shader mode", "General", val); + + apply(); + } + void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) { std::string val = static_cast(_sender)->getCaption(); if (val == "off") - { - val = hlslGlsl(); - } - else if (val == hlslGlsl()) - val = "cg"; + val = "on"; else val = "off"; - - static_cast(_sender)->setCaption(val); + static_cast(_sender)->setCaption (val); if (val == "off") { @@ -461,7 +459,6 @@ namespace MWGui else { Settings::Manager::setBool("shaders", "Objects", true); - Settings::Manager::setString("shader mode", "General", val); // re-enable if (MWRender::RenderingManager::waterShaderSupported()) @@ -521,15 +518,6 @@ namespace MWGui fovText->setCaption("Field of View (" + boost::lexical_cast(int((1-val) * sFovMin + val * sFovMax)) + ")"); Settings::Manager::setFloat("field of view", "General", (1-val) * sFovMin + val * sFovMax); } - else if (scroller == mGammaSlider) - { - Settings::Manager::setFloat("gamma", "Video", (1-val) * 0.1f + val * 3.f); - MyGUI::TextBox* gammaText; - getWidget(gammaText, "GammaText"); - std::stringstream gamma; - gamma << std::setprecision (2) << Settings::Manager::getFloat("gamma", "Video"); - gammaText->setCaption("Gamma (" + gamma.str() + ")"); - } else if (scroller == mAnisotropySlider) { mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(int(val*16)) + ")"); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index e878d0abea..8ca3ad758b 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -40,7 +40,6 @@ namespace MWGui MyGUI::Button* mFPSButton; MyGUI::ScrollBar* mViewDistanceSlider; MyGUI::ScrollBar* mFOVSlider; - MyGUI::ScrollBar* mGammaSlider; MyGUI::ScrollBar* mAnisotropySlider; MyGUI::Button* mTextureFilteringButton; MyGUI::TextBox* mAnisotropyLabel; @@ -50,6 +49,7 @@ namespace MWGui MyGUI::Button* mReflectActorsButton; MyGUI::Button* mReflectTerrainButton; MyGUI::Button* mShadersButton; + MyGUI::Button* mShaderModeButton; MyGUI::Button* mUnderwaterButton; MyGUI::Button* mShadowsEnabledButton; @@ -84,6 +84,7 @@ namespace MWGui void onResolutionCancel(); void onShadersToggled(MyGUI::Widget* _sender); + void onShaderModeToggled(MyGUI::Widget* _sender); void onShadowTextureSize(MyGUI::Widget* _sender); void onRebindAction(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8ec495550e..a1f915ac9b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -177,8 +177,7 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); - // The HUD is always on - mHud->setVisible(true); + mHud->setVisible(mHudEnabled); mCharGen = new CharacterCreation(this); @@ -1001,7 +1000,6 @@ void WindowManager::notifyInputActionBound () allowMouse(); } - void WindowManager::showCrosshair (bool show) { mHud->setCrosshairVisible (show && mCrosshairEnabled); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ae7d6612bd..ff26b087c1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -134,7 +134,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty(new sh::FloatValue( - Settings::Manager::getFloat ("gamma", "Video")))); + 1.f))); applyCompositors(); @@ -782,11 +782,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); mObjects.rebuildStaticGeometry (); } - else if (it->second == "gamma" && it->first == "Video") - { - sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty(new sh::FloatValue( - Settings::Manager::getFloat ("gamma", "Video")))); - } else if (it->second == "shader mode" && it->first == "General") { sh::Language lang; diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2f9b5a67f1..f03305ae75 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -157,53 +157,43 @@ - + - + - + - - - - - - - - + - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 26546c2b15..31aa60c42c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -28,8 +28,6 @@ vsync = false # PBuffer, FBO, Copy opengl rtt mode = FBO -gamma = 2.2 - [GUI] # 1 is fully opaque menu transparency = 0.84 From 2c3719a6f5f2a4110e412781de0f4b955e1b2441 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jan 2013 07:02:12 +0100 Subject: [PATCH 0061/1483] Disabling PSSM feature to make sure we can fit the max. amount of terrain textures in Morrowind.esm in a single pass. --- apps/openmw/mwgui/settingswindow.cpp | 5 ++++- apps/openmw/mwrender/shadows.cpp | 4 ++-- apps/openmw/mwrender/terrainmaterial.cpp | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 294921cdd0..c5c6eada26 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -225,7 +225,10 @@ namespace MWGui mUnderwaterButton->setCaptionWithReplacing(Settings::Manager::getBool("underwater effect", "Water") ? "#{sOn}" : "#{sOff}"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); - mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); + //mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); + mShadowsLargeDistance->setCaptionWithReplacing("#{sOff}"); + mShadowsLargeDistance->setEnabled (false); + mShadowsEnabledButton->setCaptionWithReplacing(Settings::Manager::getBool("enabled", "Shadows") ? "#{sOn}" : "#{sOff}"); mActorShadows->setCaptionWithReplacing(Settings::Manager::getBool("actor shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); mStaticsShadows->setCaptionWithReplacing(Settings::Manager::getBool("statics shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 3d9f132435..808c8b5d94 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -33,8 +33,8 @@ void Shadows::recreate() // Split shadow maps are currently disabled because the terrain cannot cope with them // (Too many texture units) Solution would be a multi-pass terrain material - bool split = Settings::Manager::getBool("split", "Shadows"); - //const bool split = false; + //bool split = Settings::Manager::getBool("split", "Shadows"); + const bool split = false; sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false"); diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 5ef9fe58fa..d5e531f869 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -153,7 +153,8 @@ namespace MWRender --freeTextureUnits; // colourmap --freeTextureUnits; - freeTextureUnits -= 3; // shadow PSSM + // shadow + --freeTextureUnits; --freeTextureUnits; // caustics From e4f140841e2e9eacb25c671cbe03c61938b1219c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jan 2013 08:23:15 +0100 Subject: [PATCH 0062/1483] Make OpenMW work with Ogre 1.9 --- apps/launcher/graphicspage.cpp | 1 + apps/openmw/mwrender/localmap.cpp | 1 - apps/openmw/mwrender/shadows.cpp | 5 ++--- apps/openmw/mwrender/terrainmaterial.hpp | 1 + apps/openmw/mwrender/water.cpp | 3 --- components/bsa/bsa_archive.cpp | 5 +++++ libs/openengine/ogre/renderer.cpp | 1 + 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2c4f3430c5..cc4cbfe7dc 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -122,6 +122,7 @@ bool GraphicsPage::setupOgre() pluginDir = absPluginPath.string(); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mOgre); + Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mOgre); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mOgre); #ifdef ENABLE_PLUGIN_GL diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d878cb86ed..b34942d28e 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,6 +1,5 @@ #include "localmap.hpp" -#include #include #include diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 808c8b5d94..595a82294b 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -9,9 +9,6 @@ #include #include -#include -#include - #include #include "renderconst.hpp" @@ -125,6 +122,7 @@ void Shadows::recreate() // -------------------------------------------------------------------------------------------------------------------- // --------------------------- Debug overlays to display the content of shadow maps ----------------------------------- // -------------------------------------------------------------------------------------------------------------------- + /* if (Settings::Manager::getBool("debug", "Shadows")) { OverlayManager& mgr = OverlayManager::getSingleton(); @@ -181,6 +179,7 @@ void Shadows::recreate() if ((overlay = mgr.getByName("DebugOverlay"))) mgr.destroy(overlay); } + */ } PSSMShadowCameraSetup* Shadows::getPSSMSetup() diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index 3e31b2a584..fe1214cf5e 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -67,6 +67,7 @@ namespace MWRender void setGlobalColourMapEnabled(bool enabled); void setGlobalColourMap (Ogre::Terrain* terrain, const std::string& name); + virtual void setLightmapEnabled(bool) {} private: sh::MaterialInstance* mMaterial; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index a16a23b26c..04a1263672 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -8,9 +8,6 @@ #include #include #include -#include -#include -#include #include "sky.hpp" #include "renderingmanager.hpp" diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 9913fb8aab..3bff93baa6 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -403,6 +403,11 @@ public: return new BSAArchive(name); } + virtual Archive* createInstance(const String& name, bool readOnly) + { + return new BSAArchive(name); + } + void destroyInstance( Archive* arch) { delete arch; } }; diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 3cdb005186..ed5cc9b435 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -192,6 +192,7 @@ void OgreRenderer::configure(const std::string &logPath, pluginDir = absPluginPath.string(); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot); + Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); From 35d17fdaf65b37b48fc92edcda0d6334cd1c20b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 07:12:12 -0800 Subject: [PATCH 0063/1483] Associate a character controller with each MWWorld::Ptr --- apps/openmw/mwmechanics/actors.cpp | 115 ++++++++++++-------------- apps/openmw/mwmechanics/actors.hpp | 9 +- apps/openmw/mwmechanics/character.hpp | 5 ++ 3 files changed, 64 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d541baea99..a7e8f0db16 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,30 +166,28 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors.insert (ptr); + mActors[ptr] = CharacterController(); else MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } void Actors::removeActor (const MWWorld::Ptr& ptr) { - std::set::iterator iter = mActors.find (ptr); - - if (iter!=mActors.end()) - mActors.erase (iter); + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + mActors.erase(iter); } void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) { - std::set::iterator iter = mActors.begin(); - - while (iter!=mActors.end()) - if (iter->getCell()==cellStore) - { - mActors.erase (iter++); - } + PtrControllerMap::iterator iter = mActors.begin(); + while(iter != mActors.end()) + { + if(iter->first.getCell()==cellStore) + mActors.erase(iter++); else ++iter; + } } void Actors::update (std::vector >& movement, float duration, @@ -201,79 +199,72 @@ namespace MWMechanics { float totalDuration = mDuration; mDuration = 0; - - std::set::iterator iter (mActors.begin()); - while (iter!=mActors.end()) + PtrControllerMap::iterator iter(mActors.begin()); + while(iter != mActors.end()) { - if (!MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead()) + if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - updateActor (*iter, totalDuration); + updateActor(iter->first, totalDuration); + if(iter->first.getTypeName() == typeid(ESM::NPC).name()) + updateNpc(iter->first, totalDuration, paused); - if (iter->getTypeName()==typeid (ESM::NPC).name()) - updateNpc (*iter, totalDuration, paused); - } - - if (MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead()) - { - // workaround: always keep player alive for now - // \todo remove workaround, once player death can be handled - if (iter->getRefData().getHandle()=="player") + if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - MWMechanics::DynamicStat stat ( - MWWorld::Class::get (*iter).getCreatureStats (*iter).getHealth()); - - if (stat.getModified()<1) - { - stat.setModified (1, 0); - MWWorld::Class::get (*iter).getCreatureStats (*iter).setHealth (stat); - } - - MWWorld::Class::get (*iter).getCreatureStats (*iter).resurrect(); - ++iter; + iter++; continue; } - - ++mDeathCount[MWWorld::Class::get (*iter).getId (*iter)]; - - MWBase::Environment::get().getWorld()->playAnimationGroup (*iter, "death1", 0); - - if (MWWorld::Class::get (*iter).isEssential (*iter)) - MWBase::Environment::get().getWindowManager()->messageBox ( - "#{sKilledEssential}", std::vector()); - - mActors.erase (iter++); } - else + + // workaround: always keep player alive for now + // \todo remove workaround, once player death can be handled + if(iter->first.getRefData().getHandle()=="player") + { + MWMechanics::DynamicStat stat ( + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).getHealth()); + + if (stat.getModified()<1) + { + stat.setModified (1, 0); + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).setHealth(stat); + } + + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).resurrect(); ++iter; + continue; + } + + ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + + MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); + + if(MWWorld::Class::get(iter->first).isEssential(iter->first)) + MWBase::Environment::get().getWindowManager()->messageBox( + "#{sKilledEssential}", std::vector()); + + mActors.erase(iter++); } } - for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); - ++iter) + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter); - - if (vector!=Ogre::Vector3::ZERO) - movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector)); + Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + if(vector!=Ogre::Vector3::ZERO) + movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } } void Actors::restoreDynamicStats() { - for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter) - { - calculateRestoration (*iter, 3600); - } + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + calculateRestoration(iter->first, 3600); } int Actors::countDeaths (const std::string& id) const { - std::map::const_iterator iter = mDeathCount.find (id); - - if (iter!=mDeathCount.end()) + std::map::const_iterator iter = mDeathCount.find(id); + if(iter != mDeathCount.end()) return iter->second; - return 0; } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 79ae16fc34..f1e5ab437a 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -6,6 +6,8 @@ #include #include +#include "character.hpp" + namespace Ogre { class Vector3; @@ -21,9 +23,10 @@ namespace MWMechanics { class Actors { - std::set mActors; - float mDuration; - std::map mDeathCount; + typedef std::map PtrControllerMap; + PtrControllerMap mActors; + float mDuration; + std::map mDeathCount; void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cab269112e..c7638970db 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -4,6 +4,11 @@ namespace MWMechanics { +class CharacterController +{ + +}; + } #endif /* GAME_MWMECHANICS_CHARACTER_HPP */ From 4890d901a28ff26c93fcc9a7c16f3ee2d9751718 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 08:49:08 -0800 Subject: [PATCH 0064/1483] Store an MWWorld::Ptr in the character controller --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a7e8f0db16..aa5119dbaf 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,7 +166,7 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors[ptr] = CharacterController(); + mActors.insert(std::make_pair(ptr, CharacterController(ptr))); else MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c7638970db..1b53203754 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -1,12 +1,19 @@ #ifndef GAME_MWMECHANICS_CHARACTER_HPP #define GAME_MWMECHANICS_CHARACTER_HPP +#include "../mwworld/ptr.hpp" + namespace MWMechanics { class CharacterController { + MWWorld::Ptr mPtr; +public: + CharacterController(const MWWorld::Ptr &ptr) + : mPtr(ptr) + { } }; } From 94b24f07e1581fbb0f3310a77537e274887f4844 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 10:10:27 -0800 Subject: [PATCH 0065/1483] Keep track of the state in the character controller, and don't remove dead actors from the map --- apps/openmw/mwmechanics/actors.cpp | 21 ++++++++++++++++----- apps/openmw/mwmechanics/character.hpp | 17 +++++++++++++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index aa5119dbaf..4eae6e2137 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -165,10 +165,13 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { - if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr))); + if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) + mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Idle))); else + { + mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Dead))); MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); + } } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -205,6 +208,9 @@ namespace MWMechanics { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { + if(iter->second.getState() == CharState_Dead) + iter->second.setState(CharState_Idle); + updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) updateNpc(iter->first, totalDuration, paused); @@ -234,15 +240,20 @@ namespace MWMechanics continue; } - ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + if(iter->second.getState() == CharState_Dead) + { + iter++; + continue; + } + iter->second.setState(CharState_Dead); MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); + ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + if(MWWorld::Class::get(iter->first).isEssential(iter->first)) MWBase::Environment::get().getWindowManager()->messageBox( "#{sKilledEssential}", std::vector()); - - mActors.erase(iter++); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1b53203754..206f6e737f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -6,14 +6,27 @@ namespace MWMechanics { +enum CharacterState { + CharState_Idle, + CharState_Dead +}; + class CharacterController { MWWorld::Ptr mPtr; + CharacterState mState; + public: - CharacterController(const MWWorld::Ptr &ptr) - : mPtr(ptr) + CharacterController(const MWWorld::Ptr &ptr, CharacterState state) + : mPtr(ptr), mState(state) { } + + CharacterState getState() const + { return mState; } + + void setState(CharacterState state) + { mState = state; } }; } From d4ca954d47c0e19ee767efd2f263183ddd0b2839 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sat, 12 Jan 2013 18:31:57 +0000 Subject: [PATCH 0066/1483] scripts on items in containers added to script list on cell change --- apps/openmw/mwworld/localscripts.cpp | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index a821ad4868..9c91310085 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -3,6 +3,10 @@ #include "esmstore.hpp" #include "cellstore.hpp" +#include "class.hpp" +#include "containerstore.hpp" + + namespace { template @@ -19,6 +23,32 @@ namespace } } } + + // Adds scripts for items in containers (containers/npcs/creatures) + template + void listCellScriptsCont (MWWorld::LocalScripts& localScripts, + MWWorld::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) + { + for (typename MWWorld::CellRefList::List::iterator iter ( + cellRefList.mList.begin()); + iter!=cellRefList.mList.end(); ++iter) + { + + MWWorld::Ptr containerPtr (&*iter, cell); + + MWWorld::ContainerStore& container = MWWorld::Class::get(containerPtr).getContainerStore(containerPtr); + for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) + { + std::string script = MWWorld::Class::get(*it3).getScript(*it3); + if(script != "") + { + MWWorld::Ptr item = *it3; + item.mCell = cell; + localScripts.add (script, item); + } + } + } + } } MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} @@ -78,13 +108,16 @@ void MWWorld::LocalScripts::addCell (Ptr::CellStore *cell) listCellScripts (*this, cell->mBooks, cell); listCellScripts (*this, cell->mClothes, cell); listCellScripts (*this, cell->mContainers, cell); + listCellScriptsCont (*this, cell->mContainers, cell); listCellScripts (*this, cell->mCreatures, cell); + listCellScriptsCont (*this, cell->mCreatures, cell); listCellScripts (*this, cell->mDoors, cell); listCellScripts (*this, cell->mIngreds, cell); listCellScripts (*this, cell->mLights, cell); listCellScripts (*this, cell->mLockpicks, cell); listCellScripts (*this, cell->mMiscItems, cell); listCellScripts (*this, cell->mNpcs, cell); + listCellScriptsCont (*this, cell->mNpcs, cell); listCellScripts (*this, cell->mProbes, cell); listCellScripts (*this, cell->mRepairs, cell); listCellScripts (*this, cell->mWeapons, cell); From c138e00aa250b1cca9cd8484b085df6830218685 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 13 Jan 2013 17:05:12 +0000 Subject: [PATCH 0067/1483] objects scripts are now stopped when they are removed from a container --- apps/openmw/mwbase/world.hpp | 4 ++++ apps/openmw/mwworld/localscripts.cpp | 14 ++++++++++++++ apps/openmw/mwworld/localscripts.hpp | 3 +++ apps/openmw/mwworld/refdata.cpp | 6 ++++++ apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 3 +++ 6 files changed, 35 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a576912c00..2ce7ce2c79 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -45,6 +45,7 @@ namespace MWWorld class Ptr; class TimeStamp; class ESMStore; + class RefData; } namespace MWBase @@ -138,6 +139,9 @@ namespace MWBase virtual std::string getCurrentCellName() const = 0; + virtual void removeRefScript (MWWorld::RefData *ref) = 0; + //< Remove the script attached to ref from mLocalScripts + virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 9c91310085..2fa0d4086a 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -146,6 +146,20 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell) } } +void MWWorld::LocalScripts::remove (RefData *ref) +{ + for (std::list >::iterator iter = mScripts.begin(); + iter!=mScripts.end(); ++iter) + if (&(iter->second.getRefData()) == ref) + { + if (iter==mIter) + ++mIter; + + mScripts.erase (iter); + break; + } +} + void MWWorld::LocalScripts::remove (const Ptr& ptr) { for (std::list >::iterator iter = mScripts.begin(); diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 028dcdedad..840243fffc 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -10,6 +10,7 @@ namespace MWWorld { struct ESMStore; class CellStore; + class RefData; /// \brief List of active local scripts class LocalScripts @@ -47,6 +48,8 @@ namespace MWWorld void clearCell (CellStore *cell); ///< Remove all scripts belonging to \a cell. + + void remove (RefData *ref); void remove (const Ptr& ptr); ///< Remove script for given reference (ignored if reference does not have a scirpt listed). diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 5630bfd5c6..4be2878104 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -6,6 +6,9 @@ #include "customdata.hpp" #include "cellstore.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + namespace MWWorld { void RefData::copy (const RefData& refData) @@ -107,6 +110,9 @@ namespace MWWorld void RefData::setCount (int count) { + if(count == 0) + MWBase::Environment::get().getWorld()->removeRefScript(this); + mCount = count; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f49b4bf9b5..716cd6e961 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -341,6 +341,11 @@ namespace MWWorld return name; } + void World::removeRefScript (MWWorld::RefData *ref) + { + mLocalScripts.remove (ref); + } + Ptr World::getPtr (const std::string& name, bool activeOnly) { // the player is always in an active cell. diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7e89c1d871..905e6fd966 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -172,6 +172,9 @@ namespace MWWorld virtual std::vector getGlobals () const; virtual std::string getCurrentCellName () const; + + virtual void removeRefScript (MWWorld::RefData *ref); + //< Remove the script attached to ref from mLocalScripts virtual Ptr getPtr (const std::string& name, bool activeOnly); ///< Return a pointer to a liveCellRef with the given name. From 6fc64e8a4e9d374040f29343029ec197f5323cdd Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 13 Jan 2013 19:49:56 +0000 Subject: [PATCH 0068/1483] scripts run for items added to containers, and scripted items in player inv handled correctly --- apps/openmw/mwworld/containerstore.cpp | 28 +++++++++++++++++++++++++- apps/openmw/mwworld/containerstore.hpp | 1 + apps/openmw/mwworld/localscripts.cpp | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index db4537daf9..6884aa6c8e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -15,6 +15,8 @@ #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" +#include "localscripts.hpp" +#include "player.hpp" namespace { @@ -71,6 +73,30 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) } MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) +{ + MWWorld::ContainerStoreIterator it = realAdd(ptr); + MWWorld::Ptr item = *it; + + std::string script = MWWorld::Class::get(item).getScript(item); + if(script != "") + { + CellStore *cell; + + Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + // Items in players inventory have cell set to 0, so their scripts will never be removed + if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) + cell = 0; + else + cell = player.getCell(); + + item.mCell = cell; + MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); + } + + return it; +} + +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::realAdd (const Ptr& ptr) { int type = getType(ptr); @@ -162,7 +188,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor } ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) - add (ref.getPtr()); + realAdd (ref.getPtr()); } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 1297fc53c6..e274ee130e 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -52,6 +52,7 @@ namespace MWWorld int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; + ContainerStoreIterator realAdd (const Ptr& ptr); public: diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 2fa0d4086a..5ec5ca9b56 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -134,7 +134,7 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell) while (iter!=mScripts.end()) { - if (iter->second.getCell()==cell) + if (iter->second.mCell==cell) { if (iter==mIter) ++mIter; From aa514a53d998462695256aa121e77df0a03cc67e Mon Sep 17 00:00:00 2001 From: lazydev Date: Tue, 15 Jan 2013 02:22:14 +0400 Subject: [PATCH 0069/1483] Console font change to provide possibility to show cyrillic symbols --- Bitstream Vera License.txt | 123 ------------------------------ Dejavu_lgc_font_license.txt | 99 ++++++++++++++++++++++++ credits.txt | 4 +- files/mygui/CMakeLists.txt | 2 +- files/mygui/DejaVuLGCSansMono.ttf | Bin 0 -> 285304 bytes files/mygui/VeraMono.ttf | Bin 49224 -> 0 bytes files/mygui/openmw_font.xml | 2 +- 7 files changed, 103 insertions(+), 127 deletions(-) delete mode 100644 Bitstream Vera License.txt create mode 100644 Dejavu_lgc_font_license.txt create mode 100644 files/mygui/DejaVuLGCSansMono.ttf delete mode 100644 files/mygui/VeraMono.ttf diff --git a/Bitstream Vera License.txt b/Bitstream Vera License.txt deleted file mode 100644 index 2b37cc1df2..0000000000 --- a/Bitstream Vera License.txt +++ /dev/null @@ -1,123 +0,0 @@ -Bitstream Vera Fonts Copyright - -The fonts have a generous copyright, allowing derivative works (as -long as "Bitstream" or "Vera" are not in the names), and full -redistribution (so long as they are not *sold* by themselves). They -can be be bundled, redistributed and sold with any software. - -The fonts are distributed under the following copyright: - -Copyright -========= - -Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream -Vera is a trademark of Bitstream, Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the fonts accompanying this license ("Fonts") and associated -documentation files (the "Font Software"), to reproduce and distribute -the Font Software, including without limitation the rights to use, -copy, merge, publish, distribute, and/or sell copies of the Font -Software, and to permit persons to whom the Font Software is furnished -to do so, subject to the following conditions: - -The above copyright and trademark notices and this permission notice -shall be included in all copies of one or more of the Font Software -typefaces. - -The Font Software may be modified, altered, or added to, and in -particular the designs of glyphs or characters in the Fonts may be -modified and additional glyphs or characters may be added to the -Fonts, only if the fonts are renamed to names not containing either -the words "Bitstream" or the word "Vera". - -This License becomes null and void to the extent applicable to Fonts -or Font Software that has been modified and is distributed under the -"Bitstream Vera" names. - -The Font Software may be sold as part of a larger software package but -no copy of one or more of the Font Software typefaces may be sold by -itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL -BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, -OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT -SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. - -Except as contained in this notice, the names of Gnome, the Gnome -Foundation, and Bitstream Inc., shall not be used in advertising or -otherwise to promote the sale, use or other dealings in this Font -Software without prior written authorization from the Gnome Foundation -or Bitstream Inc., respectively. For further information, contact: -fonts at gnome dot org. - -Copyright FAQ -============= - - 1. I don't understand the resale restriction... What gives? - - Bitstream is giving away these fonts, but wishes to ensure its - competitors can't just drop the fonts as is into a font sale system - and sell them as is. It seems fair that if Bitstream can't make money - from the Bitstream Vera fonts, their competitors should not be able to - do so either. You can sell the fonts as part of any software package, - however. - - 2. I want to package these fonts separately for distribution and - sale as part of a larger software package or system. Can I do so? - - Yes. A RPM or Debian package is a "larger software package" to begin - with, and you aren't selling them independently by themselves. - See 1. above. - - 3. Are derivative works allowed? - Yes! - - 4. Can I change or add to the font(s)? - Yes, but you must change the name(s) of the font(s). - - 5. Under what terms are derivative works allowed? - - You must change the name(s) of the fonts. This is to ensure the - quality of the fonts, both to protect Bitstream and Gnome. We want to - ensure that if an application has opened a font specifically of these - names, it gets what it expects (though of course, using fontconfig, - substitutions could still could have occurred during font - opening). You must include the Bitstream copyright. Additional - copyrights can be added, as per copyright law. Happy Font Hacking! - - 6. If I have improvements for Bitstream Vera, is it possible they might get - adopted in future versions? - - Yes. The contract between the Gnome Foundation and Bitstream has - provisions for working with Bitstream to ensure quality additions to - the Bitstream Vera font family. Please contact us if you have such - additions. Note, that in general, we will want such additions for the - entire family, not just a single font, and that you'll have to keep - both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add - glyphs to the font, they must be stylistically in keeping with Vera's - design. Vera cannot become a "ransom note" font. Jim Lyles will be - providing a document describing the design elements used in Vera, as a - guide and aid for people interested in contributing to Vera. - - 7. I want to sell a software package that uses these fonts: Can I do so? - - Sure. Bundle the fonts with your software and sell your software - with the fonts. That is the intent of the copyright. - - 8. If applications have built the names "Bitstream Vera" into them, - can I override this somehow to use fonts of my choosing? - - This depends on exact details of the software. Most open source - systems and software (e.g., Gnome, KDE, etc.) are now converting to - use fontconfig (see www.fontconfig.org) to handle font configuration, - selection and substitution; it has provisions for overriding font - names and subsituting alternatives. An example is provided by the - supplied local.conf file, which chooses the family Bitstream Vera for - "sans", "serif" and "monospace". Other software (e.g., the XFree86 - core server) has other mechanisms for font substitution. diff --git a/Dejavu_lgc_font_license.txt b/Dejavu_lgc_font_license.txt new file mode 100644 index 0000000000..254e2cc42a --- /dev/null +++ b/Dejavu_lgc_font_license.txt @@ -0,0 +1,99 @@ +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. +Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) + +Bitstream Vera Fonts Copyright +------------------------------ + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is +a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute the +Font Software, including without limitation the rights to use, copy, merge, +publish, distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to the +following conditions: + +The above copyright and trademark notices and this permission notice shall +be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional glyphs or characters may be added to the Fonts, only if the fonts +are renamed to names not containing either the words "Bitstream" or the word +"Vera". + +This License becomes null and void to the extent applicable to Fonts or Font +Software that has been modified and is distributed under the "Bitstream +Vera" names. + +The Font Software may be sold as part of a larger software package but no +copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING +ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE +FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font Software +without prior written authorization from the Gnome Foundation or Bitstream +Inc., respectively. For further information, contact: fonts at gnome dot +org. + +Arev Fonts Copyright +------------------------------ + +Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and +associated documentation files (the "Font Software"), to reproduce +and distribute the modifications to the Bitstream Vera Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to +the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Tavmjong Bah" or the word "Arev". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Tavmjong Bah Arev" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the name of Tavmjong Bah shall not +be used in advertising or otherwise to promote the sale, use or other +dealings in this Font Software without prior written authorization +from Tavmjong Bah. For further information, contact: tavmjong @ free +. fr. + +$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $ diff --git a/credits.txt b/credits.txt index e1905c88b5..878cbf9153 100644 --- a/credits.txt +++ b/credits.txt @@ -118,5 +118,5 @@ for the open-source EB Garamond fontface. Thanks to Dongle, for his Daedric fontface, see Daedric Font License.txt for his license terms. -Thanks to Bitstream Inc. -for their Bitstream Vera fontface, see Bitstream Vera License.txt for their license terms. +Thanks to DejaVu team, +for their DejaVuLGCSansMono fontface, see Dejavu_lgc_font_license.txt for their license terms. diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 871be93d1d..e7e5b695e1 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,7 +80,7 @@ set(MYGUI_FILES openmw_travel_window.layout openmw_persuasion_dialog.layout smallbars.png - VeraMono.ttf + DejaVuLGCSansMono.ttf markers.png ) diff --git a/files/mygui/DejaVuLGCSansMono.ttf b/files/mygui/DejaVuLGCSansMono.ttf new file mode 100644 index 0000000000000000000000000000000000000000..80c45b73e9d1d8990a842ca3688579a403556bce GIT binary patch literal 285304 zcmeFad3;nw7C%~b_g>O#y0dq8(plIO5&{GQw8*{-$PTg-c4U)91w{5GC`j0p$RJ<_ z0TDw$CLn|zL=@CfQG_HTnn4B;5t5ttt$Pz}#=(!D-}}7Jdw)FQ_txp^duuu8RGm|& z>b8UuLL9gV#Mh=x&(3}CJpBS8v<`Bk+qP=mruD%lYw)=pKF@92t!s~?wz75je2NhN z?Y2FhZW-~j-AhQqA>>`{+9NqN>%HrFgd}ak{k?{bA2R7bTavos^BqF$cZW@%>bsF6 zn+eG%BZNyCIce1R{@mDa3CWDc{X0hunKFsU_#>GppO{CDn>q4W{|)T>ON8$ z;lFe}zL)SzSbG{~A;UPHlks^jKF4Q`pE~2SGnY;Hyp<5w*W)G*8)9o#^flo( z#}An?$(Ai75&kUepKrpD@gsyYb5Qo#PK3m^oHTLDRA2T33*pOF5i;`hq{$;DH92`i zCPI$^gve2NhH;CWxKwXFOHZ$IK3kPe*1oae(+rkFIASL}w}4P?A(sPc9k&kjdTul5 zT<%TKTexkYw{tr{zs|k;-=njSH0Y>ZJ89R>T{|JCi$-_v%D(N*s5CTFvM$hQGX<%2BLJqRU&4pa1Jh<^KkK8EiQ#?$YpXZxprI^t|!-z8_bR5 z#&MIm8QhE9%iL0K6}Oh#1n%tszxHtlxg+4rIqnng3+@}PnEQdd#ogt~d5%|j3m?iy z@;*M1ufwPEjrrz$E4~BYjqk+|;D_>A`~-d~KZ~EsFXWf=uk!2oH~6i59>0gr=MV8m z`BVHy{3ZTN{wiO}m+`mxd%P+Lf>E#uZXsHT6KV+cga$$rAt1C7Itkr{KEfbjxG+YT zBup2c7hVz;3oC^+!UiE%*e2{0_6h|;p-?285k3|^6TTL%3EvAhg*(E1k%*FL79C=^ z=n><^T4IXWP|OrtitWTMVo$N3I9MDhjuR(~GsG9gm&K*xDsip2N!%jt5O<0D#Dn4y z@q~Cz{6zdh{6;Jme-Lkpcg1pvlN8A!g-VfPNU2g|skzij>L7KKdPxJMp;DGK zL7FPflIBVarRCDA(mLr4X{(ec?UC}OL();{l=P8wN%~T{DwRrQ(rxLUq{@P9lx?zG zj+W!(8gf0kf!st6$Zh0Ka(B6pJV+ickC7+I)8*&om*mCrN_maELC%%8$vfq}a)DeZ z7s+SjkLAzgujOm<_wr5oj(lGsilmqohZ3%Mlz63L0IH7aaXkGWTaiQ}; zA0z*VJke?l*50adr;kVN+baEh46SQURZFyysMA7*)_1)xRaZUd&#qNEujx!M{nw=& zJeq>(zg|M{o%$@Hk4HT}csy3iNb6CR?EXOisU`>4#lc=<-V4?-U6+D2s;V?Lhj6`u zIH^5Fq#Y* z$R=u_PO_D{X&Bi}BdM3XOXH}Y?5Bw|jU1p2=~!}-{)gTs74#1Mg;W}!G(JhGv9+-^ z<&2$-ohWbYYV1Y@<7nd;lt;mbcQkJZH1|B?QP|h+`-BTO!XrBH|Ay67S}N_7E=o_O zpE6h(sf<%5E0DYLBJi@ZR9U60RW>PGlpV@0WuJ0TIij3U&MBWLUnt)w#mW!LE#hdCL_-}zs-dx=xdGPP&;jTMKqn3Grwv1aEW-rDRKqOvo*3o=3xVap ztH3(o4PYyfXV_!NM|uc23Y-Ey0xkhx8m<~jk(L3sfqQ@o7gsPEjW(m(2z@oi0X2Yn z0PK&k2@o*0fn2(?x{ZB+LBMce3@{0p4nQu(mw?5HGD)mHlNoRT;eZE-2WkN+KtmwY)Y8<>)Wy^jbU$D) zFcKICOa^9{Uc~ift*oV>Rsm~)O~4jl2e1p+XF90ea|HAW;GF3b(-)?1OvRvo0B!+y zfpRRjI6yI5*!|{EbEMgaG!dv{PQ|q`(A?Y#*A758b1z&6X!i~Um1Uk_o@$XgE{3YnCKq&y(nQsI405wDiF^1Se+=PTg z192fWaIMG62x$<~BqV^e4bTbb4)h5bgzIqa`!S#{ zHee^P7bpMy(%#PA#op82 z&py~b(mu{U**?SmqWxw2Qu`|VTKgvZ7W)qSF8e~Z8f4mplGPB}huTylKrxauf%lsRrY?m1Ma;50gIPPa4K8Rx9wtmkat zY~lQ|W(1t)J&=P0|bOA7eLotFw2LmI4 zalm9?2Jj;AGO!d_1*`=&0b76_z%F1PfH53;1ULbl13m%10KNf=fggZdz}?Vt7w1x3 z7FVb%(&cj{y6U)6U5#DMU9DUlT-{u~TmxJ~U0JRPuBonBuDPy-uH~**UF%$LxVF0T zTzg#ku0yV)u2Zg$T$fy5x~{rPU1hG@u6r((jRm&=7~M9v+a2wWbJuX!b2o4|aR=OO z+@0Lr-F@7H+{4{t+>_kX-OsyUaxZqTbgyx5aOb+Wxp%tvx(nQe?jrXY_s8zf++Vw| zx!L%FpCDfT-5&^|-_vN_&uOU9;4SW)rO~rA`VEbKL!&on^oBnz^Kth)F8^_Ddt82S zJ0Ew?|DF6t+9?eFoo`a;L;5`}U*}s^Q2ul+f4a_}p!_Vo9Nmu!&e!kM@;7MtI&V`o zI#vHRxD9_!>*WX6^|X<^l~!E$-roxz%>)B5#~_v`%8%GCAw zuUz$6LT}F_yb97QU8Xt*9!qPr>!T+4o(+0CwKhMN)?5C^eg#WBs6Bs)^TE#s@j18+ z`rJ}ATD5!hZ}qD_X7xElAH{#nugVD;@{L-1f-Q2el?fhY!So}RF1W5B9q6T%-%IarP#c2k;yISjb2>Nl zax^+vGpp(fzUL2RKGL3`x*luYg4-N)|08t;^(Cl$`Ww5yIv&FAsg8;SmlO1CnU-Is zw>c=kil2JF{`l;l_c5rPpte2YaXlh0{r=!K{3*R$G$jT8r@LKZx~$uALwD)J;VM`7t!*OjTQ#e z!CvJQt*$9rnZfi7?b#WB$lt2vS4I3D*M9Aus#*Q7&_VqT_K2djXQPArTe*_?(t4S} z`5GOsl@qV^H&3JUG&(pxxO|^hj!(O%xkfkF=t%9^NR1A@|9{l0-=nwxPuo!StbV87 z{-CQqQmXC=%Kz&*`nZ1N{>Rky$UT3kEBy~SK_&A^;w{YfNm{R85N1ObIE}z0B3@-z zZWFHEHM+Y-x7O&^8a+s(2Wj+Vjh?L0t2BC*MhBM@OdrzjIi%gwLZe$~^bn06qS2!@ zdi0-`6I^Cn?f$mf{ZSen^_QR3XJ%c)2WU?XVVvQHXxtbsUIRT`qtmtgbd4Sr#Jv&P zJtMUI!5TeSqpNL7C&o|Brs!jBv__BC?s>$2(B-A)>o!Q!!z%l$kCCAKs%N$Q(VB*g z*68}$J@vJ6yjq#whh=gk;lHBy>kz%)fQWrZEn+_g5&KhQ3S#xQaK3`Y=QoqPh_}B< zFXAtZmf|m*#olQIy~BmjD9*|`X*%cPGHDa8IoFa7^Kaq~(pXC?QY5X#N zIbFuD=Qq$5{C)mD&F0Gm3tfd>{NeO(!bV{u-73|PYS6c&vC>$&4g2L2=yvH@X$svT zO_Qe4ziScxorv(aq3;+wBEr90i}1gzMfl${PBKoW?;F1|enks#3PRRSf)MQth(kO5 z5rK0bJBdd-@e!w;^{B0#@~BUkuYLyj82AkM8n_0045qKF`3akRw0vL64 z3xKmK6lYZEKHwm51ULbl13m%10KP$8#lQ~$)7U?s4gMeh7MwyG{=a$EN7nCGoSG3H zB(oDU|5I1?Ls!^|pt_otq_I8$Mv_ZD`5$L~0@|6MP7lxZusiiLKhTt_Ge0clPzH=Q zuGP8Kr+=Djr+=Djr+=CUo&ISabo!^ccKQcat*Run2o#UPD6Yb=VdE!}$l>Egk0L&t z#u`TwwQC*id)9h(7rU}nu+JhflTZ?k*`SX0nUWefKg7PP{=83XE5+QPKmRdO$#4Nz zigCbIJsq#z)dx@NrFSBotL|sLRfzT(T;51HoF-zYvh?#=eJ-Ehm*{KcYvOC}Ywzpm zd&c*yZ>4XO?|t8aST0tKwZ?|UM#jd(#>K|RCdSr|trz=DTu7WX&Kc*5^TpMTYZf;; zZdu%`ac{+)h&vy5Bkm`^Z8x{JZ=Y;{A!qiOUiNJ>iTnAAC`ds45YK}pk+)+FstDoi?& zbT#Ql%^zz%sFhqhvd-{2lj=NIXI7m#+uhr}+mp7h-2Tel;}5vX3XC-N&qs3Ud04iz6H_N9C8l}I(3s~miENBH;31xHPl~6fC(H9ZB(mAF)3e8u z?>Xc-;W^{^!gJO0z2~Oqo|kyTy*_U{Z?`ImJma0~&G(-0e&)U6z3sj0BR-oi3=&E9 zW%x3Etu={E@=f)v^5yypG>L@7x?&?9N~9Jf(j#^iBw~j|!s3$R8pJ&jH$E;q?zOn% zkjR&i2=OcaaDTKvL6b-${}cYU{*I7HcYkmHApbCbmVc~&3M4YuzZeqP=>I6*pFk2D zC$37&P27`2lcXebQcXytDZDLa(Csf${m&4D&MMnvvPCg>y;ZTH&m{z ze6@06<^0Ntm7^-3u6(MpOJ)1Yc9m@_+f=r$Y*d+EnN(@26f3FvK>bzyMg3X*kNTDR zY3Wa;Ka^fA{kHVW(vM2dm!2y1$ua&MT?OEEbv`cBb(pIG{OP?rhUfQ5E zwX|MooznQyxYF=acWG#;qtsSvELBRSQlXTC!$e9dOVpC`k_RRCOYW8YTJlTDosyqR zZkGJJh;WHoI#4w#JojuY7*x(<`4` zxj3x-u-3z#9C~f&cg|hbDaIG{Sxp-y|NrIx8ytYIit`zhsv2_&sSkJ&VD=~%w&obp zp-9gI*MWsVDR2vT9f0>s?*co3djQTI(Z2)bu!ylp-$5D=JOTPsq)!5^LH`G7C!jNE zl)=HS!P;wOaUX#G5Eu-c08Rs=fO7!a!Hoqz23UFH0eIycJY5dwzqzZx4PX`k?_9&n zNPn)v0=;W|3w%ajc(jLs)x*O>Vc)nt-$!}`C<477Df%O@ejGxIb_=Y%g-9;|kQa}8MH^rT z{Ug#yAO`fm35nr!@Q_!G0vM2g8)>Kx9k#mK3}nV2BqK%tV_2V9dC-@b!=O78;vs+& zbWfz=KwZ#TNO7MB-wTkFhkXa$3Y(C!?`DGDiS&7Z@fbYupnL}5Yowb2$WFL|l->6Z zXy}(`5AZJNYe@3}v_mLHdI{CLdfR`|A){I#7o=0O>Qp3%H-<%?0*>ejX|M=!Gtc=(897@_q{X2-44huRuemy;p#r zKwm-%{qWua{V$~Gn^y%5KA@SzhqjA9BeemnFZj+E2KeFM3P{lh1_`?8gS>r>Ks%6T z08KzgAVWv=nF^(0fRwbMmh`_0s0H1Spee?blpD|fIi7rkV3A0$V9%5^aUOA zk4WbN^O2A7?q3Wn1APlA;{_n!LAnvx1^O4H9|5ReF%S|DW-%xxyvGH;B_@M5BW(H=2H)2WP5xgAjKSn+L$D$1Szv}eiSN}!eVf;fp2L?hy96%ukL64AO)&C7GldX--;@0C@s$uRV#g-K|L*(w4MCw4?*+sKrRSkglW~ zd5Ux=JxEXTH0gy?-hD`4(vS2f18^365P60SCPUEvg*X$wge)VgaVq=`@;9=DY$e;s zTR0v5Hu*cwhwmisklkb#*+bqX?~(V(K9Y|p(|&S@d_ev|3Z)R76CX}SkkOJAQRp|x zBr+Cr>vS?kZiV;mHpq4|MQ$gzC!@%7(r>aPi@YRNfYd*e^CkeQM!nItE9 znJg#s$qJlR&qhq<6|xfN)iKkNHDnWcoopmObECND$g|uOZYnp8%)+~K)3q3A0Xd5v zoh5nn6{I8aL;+dE&4C_N{}qs9_@2}5E1+lT62y7Wf=lJN&L_92kv~Zrfx;LgeS}!# zW}{B_bT-729IaqfydHsQO}Zxb#U+mmylz)&gKjGKGaLc<6J#v zCNi58(1~OYhm`A%lFthlk$WC;TLh_X#hLx{TFd66{Z}BLWr&2Y<8DCK`@rAhXpahg z)cQg%;{^X4E{|)*jl_M&QQ8KwfzBtF$rJ&vP~y(-#LHZ5l)4W+U@MMI;$?9i;|J2q z*h$%n+!(1q3YGon1>@T`dWhENx{y!t{A|(_?-4%Be?=Dve&IR(2FXS!a4;D|E{K=0 z?~yJ0NwzeS&J+e~f3s2AZ0FwG-3Q07qn9zMsSWt+4f6S5CGTV2F1=<`VAZPKpU z`c<-#^YCfslUF#EwiDW5Es;%T3!R|JTTpHiI77%pJ{`4BB(ud8`X6*UkJJ@c@N21MH^~CJ5A7!M3uKCT8K+6fepwO)o(1F@Khh)slKsw>-^V8pH24dA>HZ1QFuFD|;!=kTQ>RKU7+zMJI-a|y7=opb`Xg*cM`J6zKi!PPbC$>vvm&#I{_E>vD ztUWeMAmvl|sPYnZt!%k>dopv_P%7>w9At{Q&p^BZE5AruNERysFH>G3M%$&#veb-> z`Xsryyex&L*?B*2PjmS>;jHUT*V(h;<%(z3jdVmsfl4^q9dDRIzqEG61S}$5BA_fH zaFQS>XwKKHRd-Ng3bp&SKYq@xi@Q(=bd^EVZX%o)3o*ZXNrym6beO!HClMm`xD3mk zR+Bx%>xqeuiVP2PI~{hL)e>Sh8WdfS*m(BYE}aWw&CR@&nOUC6u0^S3si=@obEffW zu2>Czr=RybW7A_bP(Po>?acaRbnfUo>c4v4SHI259esE7<}6jEHG8UeX>t}-e(8Bv zEL4Zk&FYX1>fZJ0Q2GYLdfH_J-CS`}#e3VNQ2kWs2Q8CeIg-inK!#Eyp2#)Bg@n*# zTbPq3EQ??1t&!~sUFKX#vn{b6n;^w2bws>35#tnPp+A<(Xx+ z^5UE5&xzEcn|E*8Zl1V%)9%QyXV@KKKn57uoTfKOOtM?3E7Xl{)uT!29vWt^hwO%p z($m85!G%n_2RBGEw{ODplfKECHvZCZI`Z_;;b(`PI`iq_;k4_Po=?Bo?V~Sl9O7E3 zUHGZP2adW(Ul%3~>NWhq5n5NQS94$UmK;6f&0qWa2bLdy6g`pe)J_)Er@TiuZ1~8) zbV-CAB*GrdGA7tZ4{Trt=@m%!G>WMa7j2E=4X;|`UTw6x#;f&Sv99J{4Udkh4OvP? zmx&n73C0E{ud%kdi4D42US_+g-ppVfWU{=8o~!6Pdd;#}uS4BwsSVL@f1D&YXqcAj zMmNzte_SF>qG1V-|C%cp-KF!`ah`6*yygE$BpaU zdF-NsMS*E`>()QGa8Utm(Phlo&Yj1N>AL7ZO1Z>b$8^CL zb?Z)hV&Q=TZA_7j%Im^$%(1mF`@9zzYPWF?YnVC2YzYeqG1slb)vFx_mnAi=L3%^6 zexoo-Ny|oNgG5EyT0bP5)aK*l`Z|q%xn1W=R<=-G5 zCgQ(ko5*td#u+G6s$`nRG$zcSWTE~z!qiDqD#mSS6j%?9lQq4AFd8+djW|EeO-khH z)(#!>E_dm1aLgBK>C$DXDJS1~Vt$*ZFSH&qsY$~D{ZDPIHK0zE-^MSixLAK}mamPR z^ybffO2)ToMMKUl`C)jwrES;l3J=?#l+eF((|H%#|7}3d$?!01SO}O)IUAqH6>4*g zV?QN}1{GIcwJBNRDE)X=#btr1T~|cJ*6YREBZ~pxmVD za%EPoOic<27aS&(TV9s>d%0E0ROO7%%^V{##%(Cz4iR;DK zY=%~B<2nenp*wccB~Zr}Vj_asAft~8|GH>5ziyHldhOlmo^gZY4!x6wz`3i%ux4CQTJrfk?MvF z+HDH$CVYGJ*wC};B0BTz&|^o3ouxC?MQ0f=;dwqQ%oJ8*d?y7$$(sh6E50f7W-d}7 z(MqIIGP5>d&O+Tf0fAtP1C?T`wR4B)Kh!68sIBNBVYS*Sj}dwF5O}#-{f@g$lQDyY z2TX|SZIO6^#t?~Fuya+yNpoSwrgzJaZx}|CFR1e<79LE#!|AvDcy2ysUwb~u>*HQqKH0*d3SD)QHPhy&H_FRtef5IY*O8Si zg+`j5p-mhVjd}>@;n@QZwJi;nV`gFb&BNm5-^QcV1sM08AUhLQ34Uq}MDlML9626y zPWW2S`goToN{S^>aaK>PHy#Rya%`B|ZN+zxUb>kQ_$-+u(_}80PZpBJWGPurR+0_L z#$;0q(t@_&TJSA|7Gevjh1^1EVQ67&Vd_e{(ym-rV^`BN^AH+?lv7Jhv{MNFn?G$EFP8) z%ZHW2hQr3grZ$gjOjT9S^_i z`Y}zxE2)iWO0GIXou|H}&Y+9wi*ycMtjX>!>`)uX&PWmip?r?O<%o-Al4DT(l81+6 zOb}vGIn*?{EcFg^lHeeT=?Q5}S*e9KQFqa9XK2InQ+dL)P6ZwAU(VBX4gM$*{E%-n zc`8toL?__KEy5!r`LL)2NfKMy?At?fLe~l;ha)y4M~$AaI2#`yV=G5pM~=X9RaJQB zoId|*vn`u+!&3XkC7|wfEDtqv&dgeRbDEYauo>7w=`?Ov`Lqvcc>3@*tLOGVHEGnz zAzx8b-{Flf=jG)cr}di8%IW&T%9c-_tDkz~AA^rfeWH|&*Co)$Mrdyh(iZJ?=D3W@ z4BJ9-B=0icw&)!HT4}xO?V4^U;X@-li8c=(=M6P@Yofhq@TD@C0%&I$)RQSFb3QPM zFf%K_%rYlKH^H@O`tP>*VWW9v^(OVlUq*d4YUGKb+xG5Vw_(GwO|LBMTbMQTAML-S z;u7AQbn>;2eoTx%o!(&WikH@Jn>BvQ>>4!=`g~u#KbtL1;0t06CrpGKIn3TI16~@! zhY+3*X-RmKoFh_xv4NV6#G?q3)f{iJm6x*#PcwPNjDn+}**W1fn0%UuX)}qy~Em*wzHTBHAS8jiN@%Ah8 z)^1kS;$pRObLY7;XU&~6d*)p3c+S$L>vNVbS=Tdm-<-V{FYcYQFE;kn<}=0DPv@Sd zLub7B;*42y=jr-C2YqUz^(me-4a7MmlH>lnEo7N_r7b5;%86bZw?4rs@zfh<@R$=L zn3#*osX#N1oU~AHZfK!1#z?_1e zMqVH>RK}VC9v1$XZ-8~F?IucN?g2)(Uw08gV99kafj_At%))$^74Ti2gYLx!9HM}A zzsT>B-jOLsY6wY8=~9{e@07t+GH@=MPKBA}yZG)8z7=Bm57i^;vHf(*HXIbh`0GOl z3p4pGRedxIxe}L46p`v(EJ7DGFF_ys82^YRv0@&4%b9m_EtxU-ul7hHJULO=McY)9!8QO9OW6A~{@gN2{JJ8aE)vzp@rG$vc z2p)&0#DvJmh?X&tA}2@@R^qiSv#v1bIM;d?#!9{jw?V|YEuVq#)KJrHr9R&4XSVSY zb4_5d^#3%&b@Q%z=cesEMoIPZLC}{ETGBU;`Y{|@XbT5zRi;@2H-?K97BvRTZv+i? z7B=hIuX*zP@m=-~9dtPB;FTu_^=X}W{Ono!%7&p!y7z6`r+(iFty>++Xnf?&PV)!! zYT2_{vU*$9Y(bRzp|C-m0^h0unG~pBqjr2`7;iBfq8jkK!wkF4_N4gTwZlBS>(@?C z3Xy736{BI$IhEKcI@2c zs}kmSfAiB%-|V(9e$Oj+)ho0Ebu=88kbi^EPgr_tM6V>h}{{ zw7Pxh(Cs$OT5KwWe{(?Hug(f}Es6-IpU~xWA^k|bdlj-zfb4f__R&bz1)d-YaDJiM z38EkaQi3Q7h6LWI05rkK8%Y9!c)StzQ_i7#U_M1Ci=+j?3}Uj;1Rm+Z6AY?qh51Cd5V$+Ph%@YKW!yjd{FlCqF4;go@7Amw8zbChFwKbLhG z>#=u#p{FlSsQ6{vMbTd&@VoBUrVCUA5P3vmiSR7?qhR&pW0oy~R;`_^#J( zitsuWPQ>pLxW&}y`Uc{0q{Om;Tji~2!Gbc)TfyvYukuO|uhOT#1empl(|1iupZ#gi z+BbIm^y91Z=dDpY(1RuS=FeZfUA?RRrnccuS6rFB;?*VGNVWN-7oHuy?Zo>_-UxMH z$UV!>VlKnHTpwdDg47E{M!ZM%x^wuD_sn~3Ifk|T`bcN0nben3B3aXZH@WbjQWAdG zkE%7a?h7|;B-HP`rN8=}dW^Q9G5xo6?vU5(cu~>uK5w^AuUV6>rIY9cy1r)33(W#> zfzPWSsUHWLY2yNWDnj=vp4AArq#VOyl4F&K)gbe!=K8Y7mf}D|%Go+sXAmae1YbkD zEiu+_cWT;NliG3Wx$?~EN-}sj?L}Luhtxdv;dSD8(#)Dzim(n#)&=r#E@VFTaejJ5Pi|$!WbSbJ zbIi|alUH%Q%E!hUP3VKN4J1C`tSVc07n7@2a08=Wux>;!@oVlCbFut4_=yz*xDgc_ z5tPhR+vQbYrweTz30ZZ6tYS!JAT}bBxcSJO=ttz`iHh);NkeC}VDl>!8$!%*0|n_B7v2JxMdlkI@YEBsltDPF|j%`6ZN$ue{D5Lb-NQClF?q6-xFB zIaVddxY)YhVURs0k`A52t#QzLZ8)YX&VEU}M3$@%@ixWk0LV=h}Yy>)^s> zWlufz+F8C;Ub#ap{h^ND2gaMzS|4%(u}T7By^<&=V7aA;9M6+|Mu|m#CH#I-HKS}t z^ht~bJ~aQ4OLiP9F-%Dm6P1Qs8}4bYx6;Qj96!D=Q<-hBaBxF$06^ko zc2kmAN2)C+DoyzId|Rol+@J3)_L2I?y_K;zX*xp=!vqIm&@=-aQ&|(nbN{aRfa`Tf zjo82>lEtm7c%ys;SGKi+1qUhl9Q|QC5G>YVW+Fjgfv-;*NKidY7RklBbX~EZpXDx= z4;L?Mt51rZKO)S;b7rz2P)C95Eb}~Pq#QMH9BpZoIUM2!J4~3;v8f>%B}qs&N+czO zskFY9OU^_%=wb9v#Hxs`jH*{hd#y%F1_t6q#b^kl;e419Zb+mx`9!6rp&_=r8Y+zq z7ORXuBabD$GZxD!XdwD+_xFO0=it6uKTz+kSARK(jw{@~`?bZS@_+Nr`~O70neWfm z+`SUVe}! zoWEaNIR79Gc61u%hyj|Pjkry~X~?niIj*(V_2DGd+)zq&q=##bs@CQdYUA{n1)>u!>`_i+ssxH?f?VAt0zWgLRbu*c~06I7om8#31S?E^6xPnIZO`b370KL zD))b7yjZgARF18hLs1-^3r|L4f;v{ZOOFoPr<>cvr-jhaObL z#WNWbSr@8(9X3&DL2suZoaf|-V!zjpl2PRXG!GcK(i1tXE7ys zydK5C$;Je)*VEEy@^}U6dM|W)c#fUEN45(&32W`^Yj}(%Z5YSv8|xWv$?1JRIJ^!F>!Hg=53Uh~FQ^P~&BeGSBQ`6yN(l;yTHct$E|&+`0)GVbF;H00Y}h2oa;O*0ofJ1ol|UjLK#FJG-& z_w)9xmdu_s-4~Hun0x9!N$7hr+u?ATT^xn4;D_ ztJa3)xqq3h@Y&qC8vJX9GGgF&V4KW=oliqf_<9>%?6G?6^*LAo&4O!A7c3fMh7+Sd zlx+{e3uM7H_K}6uSSY3*U47PU_08siH7|}E{ zvuVVDas1u#tdb8~G;PwPX>&L~tSvCH!aB4?BAo&?DT`&01PR_X63q+OyziDor2BYy z*jR0H$zlpyW@^R>6Wi~h4d!C&ZZ^Vz%vZ)nb{2i+qT2Bnwd2J+u{I`B&F@0R+E_4? z?*gr02MtDpU^MVX6QYfr$%JtsWATTOilWF|0?(Q8TYCw_+|meBsbD*IpGh&Z1){$3 zZIVfH)n;jV=0m%n8_VhjA=QFsGP4#6n}5R%Opyk8d9UC#vQTwxV+#bP8yov^{X|ok zDUqv%piV8ZhEm&*U`jNnb4~bkp^4a3X<}$#YH03BdeVMeAHKKHOYAT8m%A&y4Sh@l z&7+ho^GtraFw-#I)!w7(4(KhqDBZV3=A|55d~AYm_%#vHN`|zAJYtO zrudx6ggK4<4w@3mMJlmatJPK#OzH4K`YL@)BXFq2#*8cc3FcBTucFsK;e~hkr}_l_ z_Mhsj>a;KE9hleiTv|oT@*CXziWm4WrjONYL51`U)cfzg;&+HyUzL{3+`_ftMStpzrho_TrwyzPn630jrQN?dS5z`&csY%~;H-TnosQYeA=2 z1b=Y|fL@?GZrxJ*NTJ!kmBYe-e~;|G-veKDTa3q4&PYmIS@-cKi+j)&g@$cmOdj z)Q+BuGR`tETYKjmCW|U%;69|M_NuR_ukNL%!1_<=GIbh<;~|s~HAc9ovRx?a`#5MM z5H6X8$C#G@?gk_mxYuq=^2bGTI|`Qh?%N9;1+ z;h5#|g^u;%Av9cwuwZkrl~0gd&1)gV2GfharX^ptygw6R}VY4^? zHf!9vUG%_#rti)D`?&`{|4J9G9(1Jt$PfA~JKikO$E7_xX~d*Y57z8dF>l-OXFlBW z!O@t7GaEK2NJ{G7JrxpWzS4*2D|7{YjV399$Z)fPUv4!lcdfS;Ms18B4oBN?vm`~f zi9z2|;i55>)*K|Z>Ise=Av~sUd@<|8RFPl1c)`M@OBXI!Tyee5#*t^fzj1c>`g#Qg zT=HjMes%fM*I#loy7$3i@hA01^?2_dE6@nY`WV`i0NzKCpy=hZKMD4UuZ`JhKmtSAH{MDD$?db!)xX_-~fkdqJDR#V8NbYZE2GP`^38;Vo!@T3Q8Ws zW<}yxRSZ6v@EfD_#u;*+D>p(joEgA zqzJPoD#^e*mO0&q}gK`e9gw@+H|1mLL0c(+kpDsFm>(=jw&MsMkb} z2bw5hdWRhPL=?m@2~H#@gu%nrLoY|k#;Vwhfl7GgqqP|v$M$QLyHxyN z?h+haK@TNY#bRXUM|PJuMR9ZCVz`pdH4qyrZSX(Dn8r;PF~urM1m=)%F+z%z!<8EN z^^_WNQ@$y75HsXPN(a8Z+*j%=kL5=TqovXEOn!zqQ<^D9vo(KEM5e5eUcaigrHHK# zT~a88md~aa)qWLixR&$O7U+8}`filG;CUie{)9K?n~(GPINgld%hbuh&IpyC)4dce zEWys6Ve)~Rr!z)#bNcuF{Ki}FtN*0m(zVaOxarbS{qcRb3Sh_Mz&{uW3IcUTRA zOk$!W*=1ht;|rsXM%ZLxwrxE?CE-krXa#`KndRSFBpK;>NFcf4Fh?F8}S9pI!dytIMB#xk>#* zy#}57l-9)&Zx5}<#xH&^Ug(K>nLSJkL_f5Lg_ia77=JVdwy>>c6@xql%&8Au1$I0u zP3tE+90L`5#CLe^zyW3w|MmTuk?ZNLMY`XxXhp?o$(Y@vw|YYT0dB(S-t?C$*MW^~ z@Ivh_c(L!vd>6Foq3=>?T_1HU;%JQKxwM53)BJZU9o(j1tBfdL@Pv+FQ>R4>7A#q^ zV8J3TvhMm3r*C|J2JXv&16*y^23X~ar9JxMoQ@qoEZ?MekL=%YG6(+W7>tei;FFzn zMT}oI;p`TlV<|Kol@Yci3g$MPT4Od30h)76-BSVyHe#bTyN~#&&z?fC;cH8=2S|WE zX$#o9k#4k`t()C35HSn3QTLFK?l56~(^>6z=7V>K=eL^Pke^wv))(h0J{1Ok_1v7e zc*Y}2E<;}=v?qy73k0;dOjuP|CJgbJmNA}iEi&UG%jgjybeZc&_;S0jJfRSwnHW7Z z(=|%6w3nsOxYjjvbNNVU#-{$lyf2)>WA1Ix*~{u+(|-kGSZMs=0h?s5`s@LJzH4re z7iJIG-(ks$vQK*Cj~R8S=d6XlD6KcY`sJB^+k}jL_3AyOZfK}bT6?JqYO1e2F|X$%+1M+*^Rv?0nEY4YNS@DVuY62+QQP1F=ucM#SAG! zPE#_?t(EqMHl_~dUf3n+ZR%?t$&Kbm3Zum_h7qRe*fp76;`7Ei#&GbhI>tj;j3@tC?(18Q<*WDi zytj7`82B95vZ9b*@*tNRS+PNvYbWq>0eER5ZwK1JBf;Kv7%#{yK|q6}d>HmZOzdp6 zG0b4Zv1((O$q4Qm!oXYXkqA^!AakyY;@T?`^IBLOLibvVtGA4B+z1?e7?)$mkAgpg zqq4SJ;(_lYkEEmJ>2xMuilS(X(PeBRG%)rPdKne;(ZI1Njuy@l2B{Ni!DVa&9Jovi z)QRV4O`0SOuK2#9fPSd9!2c91Tpdea)BB3wH5BHduMUzMXdMz}31O;Z;tXcyf!V_x z@BqWCHvHf1Y+-g=h$X}tX0e2{v^nw4nqj$o%x*dA#Oo0uEaHn_oo{bx?Sy{o{j?Rc z*l5NhVed!#3U;vWqMMB!%uS0F@ca3kVpkjy=7^9)OQN;0y}iA?qi=|j#gXw^0V1lp z!`X-huHfs}Ydb8i-qHbU#y>Tnt=jb%?L^xiqgm4qtM{68>9S!^ksiRv zhBx&Mq)#B4XX8N$Lw8%k(LM@a3^5~twkJ|+Bb!^R0tbJL88v1xqkyX+-&kqQcTjrs zeUuUW7zIDlqZot2NZ0wg6)$k}%RfNu>@{KNj`FY9=J5!QL2It4d-*%?gX77_KzfAL zWs(vMkv3P1N%Y0?#FTF!`SgV0q$}U~euCLx6yx0yB*rK@xlrPZXlAsE3BNDdFw<)* zB;7$rte!2LU;)^&vg%w7woaHI*$h@*=N+hq+T4oOop#O)i93zI6Zq}zvCEq`UoqzG z-vVuxKiz-A#C}gNFI=_e%1=2{vnQ{;b!ByS@0IsnUl|d#a?`zR>=fdhyhDxQ3h_oa zPuMy6_k+&Km!H#CLR{faDdryboOBud-uE$qM&5)dx7n&hnOrztF8c5SPJR^0_n(M5 zY0bC4pAa1p>9VrZPLVFZLm-h}S2G(i30m**&Wg5}eq8@Grd07DB@B~0>oi_0c*q4e z>-6tjs76H8JwqK|O@E|q6qV&_EBD6FcP zcay|+1%hHo?l5-dN0`|$yKBE^-KNf?(z>o_-{sXF>BBpiT~i0PS;CulHEon;6k@}h zw%C=~(CrnCjc_jO;d@m)wAzCm53-Oh7H}+v!x^@q*Q)L?X{6)yn%$Y^wBxlZ_Fk3n zxvD;>$z{_K>c)y^S${ZkSv@Hv;N6-?yk*lRP%8?%-qG+!Rzw??DJ#UY=IFETa95$# zygno@%4Lzm%$VxD9!Kjq4Esy$Jt%zzUxcv_b6yn>f^VhuoV_1}_cy=+>|xsz@vaAH z1e@!jRDZ8XNO82<02Zx;1us<9PKN z^|)!qgZs3ZlX}(f5U#Dw4>p$-6#R(s#rA;vVE-$MG!OV>H+2~ELlra5tYV`pVy(@b zV<901lkBlNUG``;lvwzK9p=~0X=4Cg%B+rnXhPCsAZ&fjLP=@*i7cU2^Epp0oI|Im zE4YaAw6c>YzxwuxC1QR-ojUIw`DeD8oR>#0X5Uor$7p;#PmbaLaM%(yC7H|%MEcxO zVU`+oL&7~#hFa#jNwF@gz#A&PVNnH?1d{m5njv*lyfx!}Az=?atsy%PgVc+7X9Y(F8iB`1qE^S>O%F!5h5nJ0@a;na@Z4UxzCInyMK2r+ov_7No0 zX^nvJ5FS8uB(GJBHY z5upgyM!29@^J}~7I3I=KfQfSFPH|m@k-J+?*j3Y;layd?Z{*SsT{EFWWO?Yc({*XQT;o?9-w0({)2LpC*Zxx{-+upH6Cl z>WYgl6_?>?B0@NtiC}xuXh%`?*?Z(_nu1wM(|lKGSk)_Ux{5rqV9+*he}7pEt2V?i zp)Xk7@;iEDXABv8KGJgOrTzn(H97ZA`;EPOugMts?3M7(<__$i+4R)*cI(v@&6}@B!8%Fe7p59=5VC9aO807ZsG;+3O#`=-{v+LKH)cU2(G5;5H z?;RJ_(fyC_+`EO&F0d?}U63X!O^VVMD*{SU5fQPWA}T8OZtMl4i7gm3YKSpLjgLWt zCQ+j%F_>ne#w6x>Ok%nzPhzU<_4__^cbCPO&*%Gn{r>r(v|;Ydxie?ZIdiJzYS;2O z+z06^g<-&tH(S+Dd<4XgW6lB?O23_0Q zs@Ar)wqgtspNnDh90Xl=0^;KPn4{c3@^JY`cO&vj7W+t{{K)WOz?H1`6EEj!Dtz1( zm0dJxK1NO2@IG;0O0R0AFA{l(4b;zM>(@$_AFkoLZ(Bnm?Od^I^X80#@jza!5a>g= zy%-t+P)A#Uq1|u{S_5mcIJ)Pwp0n4~FHf78*u5^Z`JH#4&#b#pb38wP;K2NX_a1f52u)~F*?f6-MPkfa;RA2GpV!eOput! zV^oM90rT$MBD2heAHKgvI7#SeXqdc;ijcQL5D1E z6jBbpHy3`}UdnLXtQKHWRW#rGm$!Dfb|yr5MDJ_5(g` zrcujsS-4zA!>KcGxW>M=l5>|cJkuEOI zz1&>XzRoVbA9(tFpwPKo%efMxxSD(==KbKy0}Vc&Zgf|74iNR)3a@|)7jZ;?O}JNC zx+Z*h9B}^&=p4wcnaC;xPP*QZ&g+&|`W{E(8mt=~-Ck^7+%^~4P!~&7lT6iEaf|9VP!inZgQmUF&+Se4%;G>QfI*D=L~&JE(BFjN@gH zizu!Vwp-X2{G2~`)$CDz?yf>SqnZUcDTCY;0Uj<|&Yg&Xl0XDbg&*Tn=@oQ#zNq6d z0z#EN(h^RaTcj5bO3kd`Ans6%^%5Gz#dt?Q#Tc`Hw>DHUMfEiMUFFb z#vxnDqe;fu6r=^gRMX+*6W!#~dFUBoURtley*|#+;fZ}zy;hvms z9BBi&U?a!sPRpxbjW4b$NtltHGe7;|LwR#WkGk5=#wr5 z)Gief+!h1K5nq0V>z8HNLFFi@-X7f6LHB08m)#G)@Nwn1)BoyOm)>_q*YR^|r}oMl zId=50F4NQd&Q5&fK$&v1eoE1z)q0=#fdR#R@(QM8XQXBO8RqM}=8Wq<67Tb|@(1yh z&HgU@@Ah}{2@>wSCcU_m%XhJ`BcH^0iAKYdt zI9^OphyMAgI7s(N%jvIW{P;$Q6TT2fFWNUU;ZFhAVqaG$MR*c~R zq&8B(v7aOuohCUoiF=pSy!D?i*1u`_Ky(qt#mtJb#MTm=qT&wt^(Vk%iVqGXZG6Bl ze&EnvKPkR<+aBca>FlQ$oohTNi#7U5xS?VOqTVt;hQ5P{jsul}P=d20Qy-BSZuNwj zGbfCnJ#*s0ORdiyY`yfX&}6AlEo|JdVdt*38yaWdeCfsi{O84&ZnllK^43?tTPxam ztDDM2m8n-eJ|MdJc!pT_rAb7U&T#1Lb2T3|G_a)COIZb!6Tv+VXHeKEUKZ?+DLUc z!lFV|3Ne@kgi};hu*f{aLc$}-lL(aV8hNVVsBoc(P7o-F^cHs*_@~e)%A-JGP!6sH zoM*`4QpqXFh$%`EA|4PO)jLwS(Aui(^T6;Z^N?(&L|PFK32VadYnsX0NNBGVI*rTA zz~b2ojae*oWg`=Seh=vL;y?D8Y9Hq`@8i>~a@Va#d~Dyj2>}1g@>oki31KVCGf{X z$eQO0&TLY=Vjkue;qDd~6zCBV6c~cf;E150Kw|^~I`QcqVe&M&MR>S*dYXE<1tQvW zhr4)D@4VUl4P#Jnke|^M>h7fu@qpngP*LRPsV?&J%MXh4$~T2+Z@}LVG82hSRuz>j z_JZMNeEB7b!nmwk`JC*rX$yzKrB(hft4)`Mk_({ED);ps>qAzBDmS@pa$DxU%wt)I z3OZp&vz`XwQ8oh)XN^2kN>mKbHV-Sy&K~|4g-mVjnX{*^Zm&6=9g-ub)aBX3hvj6K zm9<%%#3IxD0d;%#)(x1`>92KiER}!_M_x{x0Z&+6CYn>-BRoCa@TrUN@bu6|czSvu z>Q;2!q0=%r=4p25j*9y&GISj2Vm=`84LIUE8dgN_k4x6SsCUH_;J3&%-**1&EqKe8YbRHgZ%6? z=>9(KH0b_5w6^j%HX7s>5aNY7osA)JNHF9XV533um_&o*{x%xq7H^{ds=|1)sUwWE zA97zC4T3Ke_0>%eTpAJ|m>psaj0;f&dWOg}h#>>r5oNk^2xw3@bC3&#O~M!mlc`GN zF4Yzo+ z4TvA;Vhq=H_JPR@J=DSBx)^n=I?<4#OAJr$!lj9`oQD(dl1&h@V;M=nXSI}{g6@R; zkCf+u92KGbaONg;0ajmzG&bBTfz*(ZLNX=s@HHTP(aew)Lw2rlaj|^D{_vk!x@(0> zcrhmScgy_d%uN%I86$pgn|Zj$hAI{}sGI^|YS(tPToT?X9xC0CRu_#IzAToo4v2~= zF22;SZ2(j6rl^pTqBru09&n$3j#Fv(;Z&#{r|$35j#KydA)J!OvEh`?*okqR>J(>G zbn-OXa7rGN@I>x!!xLR66ZO|kH!bZHZ_4guG{tp7=GsmiPXKQ_AI{+L+F>y|%kbj7 z6HV9%+U$h8OZVe!hnHf9YYTIN|Iu0>CjrizDpbbyMrI4=BwuVCxs+nZ_-@^ySl9Nz zA4r`^MiK)N%NfqLe7k$suH8~WtHhLl`~hdqR;9`E%gPliRzzH zA4R`-xf*b-7v%HA3;y?6c1 z_k_m}r1tK)W7^FNeb@9VSd~6yS*!*9Y`it>{fh>H+O@9^5WW z?9iTS8%LPip%WH#1z*E zCq+naR~EVD${)ut9%87t^4gs^rmpN?yUiH2YE0vk7thQdSDCglYv9U^5sM;BD~BI>gq_MQpD}#QDz>Tnj#X=S z#cuKp58JyrDd|v5Y{{UaqC-v3K3_I(S!~pSa8tH9v)A|1+qBN-At%5Gn&gCP+Fv-D z@%1O4%~0V$6RGXSffa=a&xnb$`1J zzdE$*)EvK@%__4?ybEVd?PJoM7?bAoL(E3AsC8G9q+s=H!?_Jm#3(kH3%v~9UQFTc z;i*;X$mzk?VDK~O4L*85KSQqoe?PsCx7yb;#7p5DQt#HOUftm4`*>$By`LE65;8)vZj`a)r@ zib{=2GDH}VkI;@;q#1kb)f0EWxOMmL&9HD!Q*Na6P005rK3>X9rX%4cT_0`Ox^~^x zo~pPj(#ng_&0c5GxI8+uXhG;Yyi3K{qKl7Ij+Kx^@4eTNqT)jBCBg&jL!g?@XEE)A z{d{sCK)ydE9row`cH91RXt(Zt^C=U6R3s9So2P14Jm%Lk15QUa zbcyW(c|vOp3FlojF$Qh0CRF1U-bd?Y$m+s%N%zSV5G|~C;vcm42^A195J|!fE5HQV z%ua?W4X!^nS%R!tHW@>lDkXFppR;kZTW+vA#eICW`?TlcyIpIIpVfa)|MN4*BQrJa=)m*6URgk1n&}y*3S>IKebG2x zly$(1``c}J(V^Xr7p}emBn7BEeH8&RUda7upE0fuXP4uJOMpS(`y4RcFe;$PP#9n~ z$aum1dpH~w91cDo&N%lWg+H?0hco~I6$qD^>lZM;sFb>g*=F0b=a8q?v z8zszPfCd}^(9pbSuLGZ;_TjcC(9UysaJdpUOx!15RFw1k9_?cU-xqKcj54QOhEwi8 zOB;oo-V(M5f5CGY$KGF{X^6b z?SZTV;CSdoYaMM}Q!We0I2TUs;N*O*<^CM!{@!24EswwV=X?2p{(LVx_6N=(KMKb= z+?r*GXm8Mt_#|pa#%k*fcKB&80Xg6MPPV;-EHeh}fE>K7I{Yq&pXW5uOy#%;Ed|E! z%-eZ<58*CJ7ii71zOSu6&R8O~qqjr<_OsNnKY!l`^ylx}aeT{p%CUm?I;2>3@6-F> z8HD!7;A7lPh6wLVxSQJ!KX5b_0Qoe#AtwY;4x>5_Hdjxg92`#0<2&@vM}I#>{!y=D zTa=<%GhHzn+49Aa@%S6^9AS>PamVt8u07jqQVU+l5ukJ1p{L|3P&c|6lp)Tl1TS|V z7NS+eBf|qE<-|ATucYszfU6rB)QEH|sp1*t!vh_TCTOOUX7ns zS8v|D*>v|g%D|#5Zfd%D6QDpa!x`uCN`ZhR%-NUXmApJo=-t)z{-?Fppe3!hPVcPt z(7N^ug8BN*Ho$_b9{~c*{|$gaE+E`-kBi>q;!ZA4fDGy#?h9lKjaa<6g^iJ(_*+1e z^0%f13!0>Jh?2k_&>d8*sRRyjZ3*@O`YA{C6MrV>t+T~No zJ|y*EHzB3+c6qFLJ0GBtpaF)f8%9zU3T9E}k;gD+9|s=L@%eThAV2Tvq#!<`BKq&} zyaVmGKaX>TJU2KecoOGi4iQzn<1w@&ZVT-Na(j^@yd1yzd(eEePaHnwXvjxlW-oF+ zl>@xw_%02+_9(j^Q91a}l8FjSpNy}LQC+r(E{un4?f1S^zNxy7Wb>5G3Myfw$OkXT=i@HgLecnS7*1d0AIggeW(fHzKJ*9OvE=iZxX+|;qrDH`9dRj>YP+~!qbde z4X)Eskua~4(8s;sg!;^t{l`Q_N*1;;H}^nJj@i;x7`Tdgt>-A@GEkF7$#&(Bq=lIUm0h1{cwTsXdh@ zeXzHmS5SbF1kpEdWW1@pfn@7esBv!S&Iv6s7U}Q7Xe!&Xh2vC(i|;vxrnOCC%UKtT z7mNMwyB#}19RtJV_(v?qJ5p^Cgl(U-X5xv zfVbVO?YGg6xHnF>Hs7Pa48mWm@o>NcSH%V7aR0xIhf|#UpTglt6KL0%;{t{M|33(a zQ;wG69K+$TRu^$bXKJQ^F1#px&*p$GAae)Ze2rXk;On^ueO%-|_xAEWh3G@{*u#My zKY`pWR(gzaKfqce?-A|61X^htmG)*2+7W+8?RTl2Mxyo)2oB<*E+-X7?oE}Sp#ErI zjs9q7d+wc-pK$E2n9oKlR(I(C67@&>2a3(s8Q4AWUm71cpK1<)3Kv=M5E%lkyA!Au zbM;WTq2_=FN#?pEu`GEmc7sGiLJiLUE%G0rBwP^&NI0OsP>6nTiKP#c=2Fh4M~YB< z!}8e2)1)7e)=WsRsohO4#fS>=SVKMhUrj!U(niV-*qJ>}Xes2-)y>z_TU7ffb>MyO z&c38TZi5b4_WYxH$so-0FWNk$5rc>X6PzXh6niY<)grc#2PCE!Nwcj{iLBG*Y0OE8 z+iW@gajo<{Ut?LfKbiI#bxcT(aNxIUl11nEXwX_r;A4$9V6TwFiT0{9?G<|S_VZ{D z5=>w`}l&iSfOXnZxW*yQ>6sSW+e+X7O= z{|1l78nBjJgTr@RDxotnJ`(I2`d`&jKf zna0vK2RJE=#FObh=BN*`%8=G^w9P1O7*74b!>#@7b|04uoafSb1hZZ5B0R#|2@X6% z60h~Q-R%3C-IKAx^2ez>P}^$Af0@a&$j&Qp9mKcYCW zSbJzjBJ?IB>7`;A&MBQ$xKQY{2r$qoU$HzXefaAgsFzBR2tOBbInuv2Z1`6u9K;8* zMz)vb%SKA&Ltjcw(*7@$4?(K*!2R$P*W>!aGBC;9BQcJ9T^b^du4x8^aYN`vSH%fK zkZXOo;T4^_J~{4mOn5^Ng_s!W=RDA3cBnYe(A#HVmzh0)96XB?4!Eo|;S684KSO0J zlN;+-pmBF=y^CPR;Ekt^gjx;n0U6+LUOF~49G41pN`p{TI&7e{e?m!7^~9ng@sOk+ zH@#>@T>9d?v0LK1FB|gm!GkXkUltd!eAsiFg-2W?ogZ1VZg;HZ+XFwc@FP#7Lhmn6 zvo%AW+?qWGrj%WsY^ZrJ(BQ})U*HSxrJB&|vB=jU&a_<7&k>prXPD{{} zXoS`m8`7C-oA{g{J_+NfZw913lx<;;eZpx|$72 zw;hPc^(0Qnda96w(oNA5r82;cZWB8q`4=Y(zu{g)=ZQXf8VYODF64v${gU)MzEScn z%h`jLGeXWm!HjwM{D?gbRP-`K$)p~z#Lm&l! z@CXom!4V<$N0BRXtbnXrz}*KjBo2TakebQpMnnR#9F+RS7jjtY7hl)|Q@?rm8y=a8 z?-ZJfHIeOnj`yH6EU30Q&d)iNC>Y&?KJzO2ekad`R3^zLW&}8!Yc zv_T%9Xah#J(FT$~FfZkg@kBlaUxmg^c|zq@@A|mvoZyZ+kqBwl&~b%DP?lCHaSZq( zS00c)&K6`S?6)S1L22=U%JX+Kp6Q5er10%kJ_R~N`JZE;E9vy0{LdO| z{%1=6Z0ZyhtG#mLN{`!#H)O9~A`?)UaCcr?;%CwJ!+jZ`b(BSi(v}NB^C%VcyjeUI z^f}hcArg(6Z$=IlJH?a;79&yty+Zif;F_|jq-xz`nNU2;{DUw z2|rmb{?oFleOm5X>}w{Vx}-w67i;E1(lceKgp}JoDl$AONojy%fJO~>peV-n{&+M$ zzpxPLuGzxz$*WdTlI#6!2E7$;GpBOz^tx{6O&m2;B zmlqm3mp|n*B&o~aGkAAq4L(VUxK<>u=|_3If3&CZ#+;Q{@0qHHX|?4!QIrABI~}LA zn&?x-vku9+`t|nC#FV%%+?TUUh-PWpy8d*JS+X_9mbVLd3Zb0qr)|1_`kittdx0}6 zY>OGL<8Mmm!|qDP`h8-PT@`_84kRcAceIU=ZnVi(q|J8;y6&X+<<;auD?LByyX%nb$|8)cu%D+V6Jmq>x|zKF^zKaDx&s!@Q0{O2sr1>7NLmlayzH@N z7bhjI#ja{G327{;pbw%(%x>x(PA-t_lslaMCD<~v%lZQnn~*1P5b`dZL1OlYEklrc zI`*Ite2|?wh;`uiH=Iw(t(IwaLk_h>ZHlvRq9U2{#vo9Ucnzw8QO>pJoz*+sw+H*~ zVE*u_roY2i=+2!h;6ljd;!P|F*=?+O`sBkZc>7RIsMOh__xkNPp*T{O-zkam2lZRG zE^!vV8SM05W-w>IgM+&a`GVyn%HeLL0EX&E+hY{IJG}oD6Z*UnMUWa|2)x_)LKiaft>PgEpnefI7*hFauWd&O#`dW?)Zk9Vx2pnCH15R$U$ZQ{O zRRhp_lP-c}0a!bkK9=z_OJg~VBXXvnO0+~ko;YC)RL95^S6p(uU&5rwNJ095MGuR} z=r_h0+NXw?Xv!NGcy09P#`uH==wJsmS48OpXs+&9<6WSO(KZ^z%U&Q7)lQ}~e9hzw zXbJ@gnv@|Wt+v$oL6xOCou|HhzxR-&SXOj!^o7^XzSe6(^z{x&@&k}c(H}%BWp&`+ zlI07EAmlSTp&9_aot{9_`IwB!TAp4biNQ-TDKS|qe1r-HqorIHDaBuBv)HVUEc;%& z{-&^A%9du|zKvA;w}cidH`=xz@d_`kU(fo==O+g=YBSan#|b{PV0N@-a>iiNw>xT& zbodK!MEHe;MW%YE#6A7k&ZT(+M)m5yc>n%^y8NMY9urPTHyaYVD}@2Q8rkF0_*f~aW$r{89MJ?Q=0@i*5$c(;l_l@H9~JzQ6z0-|2-p}kxrap&xA?ai`YX)&M060xfYokUJ=e( z%;Fn?E3>|FRW)0WIwooTF*U6fv3M@uRZsrlwMrCHLy53+9BtC zC|}G>R8S=PQNneZM1ydTzfV8@^29KviYnDx2VKNNcJ|O{TR2c?`13LwxlT8LHxTb+MB?)v?SYjYa?)K z4G7Z;*Wn^*6c{jDrdFw4*`VaCx2J9S^10?|QraiN+RXLq=g(iiK2!Kc*fZQ?_X;W( zu%~U#S++#1+-S?_kBgk3D8(8+3mL&%VWc^@8dq0+ATS;0QJ$ebMpH*8d?_fI2$NiC1k0J7=GtI}-p(Jag!styv z1QW?kT=v)k7JaNz=->E>2ZB%)o1{N@-g95rCKU{r=pO(|}OGr{J{m~&oKi=0dN56tD7JTgcW4DO=JCwTmbkgb4 z|1kHL-ktKu?1K%}Z_S*1Wm22;$JzI4woTo?sq$onYF|{;e=qJi9p`VHGkxK@J_A1J z+V$qulnMcw7^456Vw`jO(RvlxL7L=SoM`y3%b4Az_VxmbYx)nCBf@# zgHbu!Ar)STU24N{ia5MG)k6T!=RDhSedX#0#PI*~RQYhZ2*N8%va%X$CY@Jhj`dRwVw1t1Lcjm2bX5F7(Jx|qqXti|n zC1j<31T~G)USg(IhYl4;FZ}yU()xb+Z#JOdkUZB;%mt?y(oC2*;(!Yh0pa6QRb)6a zu)hvgl)u@fOZm>`)$=}DP`h~xq#9-R-FNZ6*3snIT3+JtW4)ATRUhzMq)2<1#JoGo zDdObcUXTXA!g609H?>>WqJ01UE@9C@p-IYFQfEq2FQ!_ivPUj<_Uhri8utVMN9*E; z{dhw;mH3wmiRI*kT-l7WnROUms4ecFw`j|hf+0yJDg8WRc?^lgu}KN3@yS6!zOmZs zOFc7p=B^$>`OSnEm&Ew`=(f1H#_%~B0XyZ!Cw`5z_Hf-mHB0z!04Gg6zr8g3Yw7nQ z=_kr^&%B#i7@NaW-CK^5l(v&SE$h)~oMhxnvyOuy5HyH!sG2=9{afsc^Oq*=9{w|> zIr~)ll|9Ttd9E|*NR#y5_Jb^-iA}^i2i&`*d;#!)s(NE%jI!zoug;}VMkgFsTqRx5 zZ&i(B3#+OsDw~e5I!lPyDy^+vKDM+7)yTd^9M8M#`Azxw*tB{;-hOuS-~p+BTI`hS z^`HFw^C$B9I?TnA8Tfo)KrbDq}hv0$1Y~)NId+kxxliNJV;J;)-!YiwOf?ymCus8#8F(M27OBA0;)JLZ}{P?FTQB~>Z_-w%&uK8{qXE# zjZZv3t_OReu5c9dY+^pr?WV=SwR4Z2T(Ya*q0+h>ESR8J3_O?!{_R0G5funilAhBI zoFFYjLN(4vS<1KShLAq5V|J||@l7-tXc*0B62{>1xXJlLmduyzMA54Uq^ z5@EB!H4%TMr!|Th_-h8|wK5!k-v2y2Y7~NKe|}%b=Y=)*J%9Ia&!71ppMUhe=l?$c z%lADWC9I}ru%C#01Y8TS9>bIiz0~X;|6ShS_H~GoR{;I7-{{Zx8S4-wzdPFZcYMy; zAO7x&mGV;$dJgklmWL`58~s@hTRf1;IL1ySYjMtA#Y!YcH|Pb zw*w2?`vZO+`=C{`y^j6c;irPZyg%oEj`Jdln%;}kKJK%~;TM2?yq$a*FOlyzd3|I2 zFRktJI>67uz7C)TnOM)Qpaqa&Bfy_X6Jd29)j=}^G6jcbG#PxwsVV-Z z6V*LdEz4akT|IGv#lBEtSW`Fwc`Kq&{&++Ez`+e{>~>2JXme0!vTe5X;|5$-=pCRb zho2Y01gzsQL7RehvQx@ut~ZCN*!m9mhP{{H;V0hTVeh#whx`t%k3jZ(Gb~~-L!r!rfJN&l( zGOcZ2A3LrCS8_Qn%Ijmtb+lIyZMKfzv48vcw*GYX$QKCf|2C~#vJ5AyM*9kk9|icg z^A#P+-)j@^&&Ti3A2b;KbJ2fChyLw83G)8h&P=;cf($=sH6P#3E3EK$?B5Q*t^Wqg zXI9^yLmbK!>o`}@F8lV#?WNZCIJC>YI&yoewS5KJWnY~`!)YCcQ9I7$V(5#8K#l`N zVoIHl2Z9_m$tj(ziLyLda%z^C+`XF!nK&789@U#iT~Z_KKJ6sRSAN@YktLk0SUi2y z%qRcIm{6S=o|>N<+49SeZ?Cwt$k4M^*w3FW){YL_lUm=ft8o0vq}*p~0&>P} zC`m0%3Ug~Y-BfyFS;mAJvjEExsgT!k>JC^!L`oz!v7RdV0&OiR>+>KILT* z`Rk{Q>6aPhxxCxx5o1Rrl}-0A-7wVMn9+Aak1qW>2fCz}?_AaY(J{3RSRR~T!XG(4 z#7676%p=niM;fZg=j*uz>q-8h57uFNDKjs1aPItTvg(QZygHF3`Q8-e6S(WEVch`r zittSZwG4~$F+hsbYoYg0Yr<0_gzb&UoKz1#k4wN3JOY=nGCwjxNEbay1rCr3SrLxD7A(>}DFw^vH*Y}23n z@RDiR_e&U0i#w!!Jor&L=v`<$Yo=@`+jy2m?J2YE$`+nG+fH-2&&va7XuHpgjfTDo ze;|sHf*%|Ak+IW6v{Q_ftvwfSPdFjdtOv;_phko9{ysLEXNT`TIjF;Pj_|R6^Lb=m6%ShZI$t+PmAsw%E49lJ zvcD4U8GC@IWbaUOjxJ-V$Z?Z2bCB+#VzHvEa9zg8&A~uL@1!WQesJXM#}QC!1mda2 zYrepJh|LjF=kbdG#UTvy0rl2O~7j1ht62&yhzyv2dD zlouBj4IW&?ftz370l3VHfN9(%h$^=Ut3l?d)?M3?k}_T^M$ghw>JGq3ucGW7)wCIG zfneF5562UlFFiIY$(!=(K==3FJc!qP9-O1+n-l_pH=&c0-U z#j(TR!8P}FwlGghyL*?dI(4aEzdY16G(FDD7JuNHE#Hn4yw9LHqANR0$`F9Vjd8Go zdc&iGoN_4XjYc0CMV1KCC$Z^5cdwzPuU-(|=bk{josUhtQp~bh@QC8{w0>1fwK~fN zt$ysQWzP%{1hJFa2%W`SODwH1F_&EL^<#0*qrMrc!~1v!ROKBX;O^G8B+B?0xgr53 zTg<+OtnSWauYw}U0i@&ygS3s^$m)Oil(2_83O(v{zT$cxUfFM8bo8i^Gr~-kTkf8f zRNjwm7gD`$zB^bN85`T^{B;2nR=&*O;H`Jn)eT&|D#X{aRPQwd1^*bWxsvL>yVKgs zx**aALFs6`1bgzI6#N2hqbqI*zND~(-!Fd$6Y?0nfjmY?M2RO+R+*lmHKf|%Iu<3o z^~*1pq^?S*ZdFlv((Fsp>WSjJY=mW{u;^f~ytEq2TNWpF&2p!N~JSxfAOifOoc8`e4K0 zHNO!CO74wt&|`DBOBQT=a^dgRRw@K;v+X@87ylNdt;}T$oh6J3Uq$RlAYqob$(H#S z3ST*cn77SsQncp(jb#uz_OnwC-jV%w@4oaMc};%zBY9B%_#NV8j<4J82hG*JjRSh}l4Xh!9Xh zo{C$)km?Gmqvh1F z#6UNJSu7`S+;AvrHKk&2la#?OG_gOdm8}HDPONhp&I;9N#fh~!uLYyZgLOo_5O%dg z1W7l>q^vznsG54Tr6uFovO{mS{rtz;M=Q@(On9km{c9PhnHp=WnJO&($C{~h7p7X1 zl*a-!Q|-0Ts5a=i|Ft$KaH0dxqdF)y@c*$k=*GMI966dpX;9$Y*?XTt-!&g=@%I|8 z=l;LdaNTArPipzxUbD0dYPfc_mL?VEIkK`1D1-%gY`(#+(699{hl=%Xs3_}4C1w3h z^&xUq*$`8xTv#@OX90sdH@U;c!JqpU3gI9HSBH8L_d99Z+`RSwP-OP`r`~KSFaM`X zv&tn@B62Z5FD=;10PLkdc2e!_rIuZDDHpogn^&IYHE8RdQGxcf)i>8xaQ5%cxv~tQ z*0kg`mM|rJv_6vBigpgl-CA+v)JtGUW@SWdtaMSjjei#%3(gAA#m-dr1RN&9XI1x9 z5OvOxeeJG#IGZU+M!gTz`D(p4a0W)0FxKqeBYqp_e%89S<234_=ixnhtfap>HY4xR zmE$*77l$Y9#YG&P&pPRiaT?9h-(J@B=)*$2d*ox!7UIs7#^pBBDA}Yo6-ZaR^){1k zh<5RaWlX&~efm|__jq`xTy@&Y-2M@nnMG75pm?EOJo7+N+v`^I?%u&&V(rCk2~X%8 zrD9GOo3sQK-8Fm1SfURT?t z@a}TQb2Aw4CfM}Dpn_Vzc+7^hxwnDv31(dr< zg?e#pQKwg7uhT2N4j}JHXIa>5`wpT`FUo&o?Vks}ITOA`kY$ZTzC@8ch(I(sTaQfE zz``RKp%h@iMC;m>w`J$G z_3vb*NsWEO%f+^@XK!s7(|GD)@#r~#;pImrHnJC^!^Tw~Aq^8#Jag|`Wi;T3CraU3 z@20KSoK6fpVMvUuk1*ADZb;y3+=lhy399!2+U3YA7W< zL+mvYVbV*s^9O4U3er@0uG}VlcW>y4(FG@}4j+GJ`|hXKZr-*&|8VuB7mD7yvs@Tu z*gAFp3qe7L!@?(xEw0@>EHkgvKk#Wkzul`VACh5C!`e4s?csezn=gBOV`ltpi?!gB z+YPTkK&#=8V~Jh*OV%XA5nMGcEv>rxjCpNtk3N0!m-p^#&Ym%6(S(!~G^gd{3@Yr? zH)HpRe2-_=2L}}z<5%QlzOPCEoOyXu_g9P{NOfM_lgAdPrf%*Mo0%6I>*fx4-P{Uu zCal=nkN_vI@{9YJItRcDilg_gD#O6@d`QA$MxEA#JtkA672@uZ9fn?b;2d^!d`ihVI?-#^kYMCtuq0#8Byb@w!wg<)o(<6r_ag3Q65L zb7r^0TPHpo81(SOtw%D?u`;%v?>B51${ApHkfRu68Cy+aSxrHz3gryx3Arw@^bj%u zqe`(*-6TbG&cm+5Nnw+O?CYSrx!lh`lA>LZd$8ThjNBdD5y4h*8q~^L2U5VPrSN@j z?&^eqp20!Y)o*95?p?S%WnOLg!m=apzI){NYg1>=tese^tTbAkbMCg@U9tSW+SA{# z49myt>Fd(i4?p7Tx{Kh!dpVPB44zBYnI2gE8o(x*#6{8{4=#N@d&WifjnKn7`hzN8 zfBMuDm_)Gv@?n|sF@+J72;|vF5W>0%HaBYp1TigY5c&w8v7p$IPu$pD84LPf_YvgQPS-7KJ|A=GV*+xtG?)2*FY+9$6pbOSxJm`WU zn74b~hNF@hFy*C|DX1UX(vooasg2}zK-gPlaG{!OWvg7vb)CG5m2pX ziv>PXOHJLfdPq}EZ=WhJ6VJII$Ih+xQsP$kKiTVhb71t~|2@Boefk^yQaBFEn@wRJh zEPPRFQK5W_v>Xm2pQ(Mmc}sF>k}hr9#FCrXBz~@6!+0)OV-NUs$sU0;1~EjX%bWYl z%cPs^dRh4?IC2T;8!c%|D86eC!GLF6u`hJ7vCh3md{lbWI^kAj<;J$tR1Y2fVT)1D zhn_PM5Zk0HC>-q^KGDDd2ew;FI7JDMcFWDW{%zBVZgFyrz8J`s?B8`2{nq87eBaPX zZ2OkzY!v8z&4rihQw!@hw>_PlnS}y=T{$l9!kpbPr$3!CM{jcAB$S(cLaZJ!PoSo7 zaK!LyUq5v`OZw)w_Ber zp%+&^a+@s^PDw8enONA@{L9V!!lI$Q_Y8Y%PhQ^2dRAt+Z3PxOU@7N-)XD0#<>ei5 zJ|S`Yrj_|{=YrXgDXOtHHC*=Q@o9haX$MijakII!Cx%t$t*t%KyCDr3f8m-J$V`iF4dyf}gXaA|s&2|z}ow9S+Ti*BRo?E{$x4Uv-$NKA!P91gh=%}fdn=1>aPAw$a z2i!$j4;{W7dn*$hB04xJWS~XTTNsTa~!<)nKBaZA%5(Y&QB?wr-=O^K@pZ1Pgv~bkEpDfis9jaQm zuBSPjOL>(AJ1uYnf&F1X6g1asyrBZsEh0f>{Aw?-G2Mydmsh;hUo{NngJfw5yzs*Ot zKuG^wb4+(v?QS*rBG+QMH%wl&D-1V#qiMG*c0Ry9B-HQMHe z^}%j$xIXCV5o`POON`%YzED!KVA1vJn#i!)uchXu2@uDZ_v@F~{h;|!LBY+pCmdI1 zABm2}{N{*GCXdbo3)bx_AEAFD6@k{*?j{EWcI{G}9~~Xx*(oo7`R+rIP5~qNoeqI) z2YJ`VM<~rz3Rg}5m)@7}SI<08NgjOo%}RN$4XcY~i39t^O zQ+B`aww5W6+VRddX=4!|-ttsCe83TsJnbxpLMg4cP+#HwsK{}bKY9L{u3gIs>4l4J z|Ctya({Q9kbX#Nw$`hP|qC;GYiVI-0=@7?=uu?!ulFkADg|z2qEv+?qwZ3r1E4k#j zbeVaa9#(w*$kD2ZsGUhU@rKtQpJpC?{XON8=8DpW=oqX9Q|y<{DPzGiu$DLr5V5Q$ z!B5)gI3gvAo8vEzDSW+ z)ovJ_@BYrmP&!ji8oa9ldZ){PgU5L39PJ|zus9!qBuvH;8RH&q5qh>XG_>>{K795o zuM7XRyq=Y{Xxp%X+!!D^u|FgymnMi!LLnqu8mb*}aZ3V_8|R{#C5`c3oPEbW6&5_~Gu!bH$gMZuFfr zZOs$s#*E$lXw|gr8%6A{-^zpmlQwF21iCuOxlc@3o8o5kE}x@q85gGOG-mRB9e{JymM2z z^Bd#&!`5RiHQiCTl}EY$0_v;mJI9*-5)ZXed;sm2Ctx~R9?KefTBX~9uuduK^w*tbnl(4TugR2xxg{xy$K&eN!{&3Y2+p4VkwPXv~0Hg zBEZ;6{mn8glUg6%J(V8EZnGpPc@4g%D6TbE3kSspQQ9svQ-Fe{;JJ*C zKZj-Ln2*nqeq~7+>D@8h7L3k}zrDOAWdx9xXpuec!ge)LlE5WjO>AUYo=q52vutcB z_uj7@S5-6Q;?&dQs^HpxgdL#?*^RW$Qz?E#zKI~RM81k_Ie>SVgn6p*4xRX|2ndT@ z4DA;mdKFTMkgm=b?-v!XQK#a{rhzsgm3=P#OAuJ+-*&t4SQb8+G=9=URYQuSsv4qw zb~rD7bp_jfdYn}7@?DiOy>r5wGjs2Sl&dgVU$fu4CRqi;D{e6%Hz* zn1!CDXT^}V&xHDrxib%*TD;3k7k(&K?^~C%YHUHBj8~51C+Xy6qi_i98h#;;mP(Q> zJADb`PhBs4&&MBBXd7R+BLdQY9v}WBv^GRzKtwtMPSf!j{vchu64!v%|8{eu#=uimu9;sOgTfsob`Wc?q*YZj6dlES8ZY3+<4>{wFow zc+}3F*RSl{DP5Kdr8kd{uVMkORgGW2v1wsHLge5~shhL3J>y-X$!!)2_if}d|4X6$~JJ-mEXUO@_H zwHI_p~(4Tld>zS*g5Izq1oL^pV_*0(qd2l#@Ra$04~xAU*kGqJ-_*432bykmTi)t z0FF}X5UvzOgc((?DIEr_pO84ShdINze%-qD#td`nY&K*bg~F6>Ib2m$Gj?oERn_6` z;`NlwovF|Xrwqz7r!aP!?VGtnnkOANmn94 z=Ts(oJ+X(mGtWJ{ywoaoy%GX&(vGb)k-cmRPpk`5Yz91Zmvtq2%-s@RJ-L3PA+kppMcA$ZB|)jNih}mX?<0)85I&$ALB; z=O8&G9iJeSjJBYXGil9{>o z^wPrMpp#NecJ{~F`1m;cKvjIgzI}pr-@b(Ss@JSZME?9p*(BA>nmKb8+m5dsMjKrt z4Z2Ni{yWXYos}G1;AQbowDYU4TEDpUVETEbNxIE^NF9PTah#9tz=U2Mh>@%dpe^JR z3c2@@)1wo5_8fMGM~1PMD-WV~(oXw?q9PbF+)m(!2B#m}!hQVUOGn0H?!Ie+u8FU_ zKv|@K?>cs%>bddbpJP6?f~z!!Jz@D(TWLy98?%Ec|G1msYrpm(!kfz71`aB99Gi1 zU24($#==?vQ6|djH6quO(Io-3-~ph1Mqb&aBHJj<6r80olRB+j%P#s073_LNcuoHN zhKBk1HQ}`^-mSWGvVEC-+9Xl12{}m_g9EWeW8~!?QzcaXwbUy2G+?jO;G+uR-O(q_ zVL>4saw(Twoe0C|QqZoiwU$GJDNgAVH$J7LBz<_q-1x+;%Ts!$WzASNrnq?8=bv}& zJ2`7k`k*19fi;m6N32rDKJlI~T6Sf%>{&NxU~=+s z+!;H?cy`)my)ptn8gTw8Z&n1?Tj8dIv%n=-@Bq?RSt-2fY!6>eA@F^O2g+umN z8#4$-%bxX-QA9_N-801T2nlh;T4YQo)*yLf0w zuSUz7#Ae?r-<6aQ-z_dKE`CaSdb(1XIOlnGF(Fp0(3pbiXf>JCsq3)9%&P;3eA2Zq zLA!jH&I^K(uYN|IG@;Js_90de2}@jNUC_Vozz1Z~u0NROaaveTQ`TS|bFq%VO5APj z>*ip@u@W!)B|4a;3%0mWW&ebPDGl}6219<{@ak#JwKX->GbYuf$2AL6qmxtm&B{ne z0q0yR4TUOp_h~3%#mjARl&A5&S^-lRi9xv$A+wxt0-@E~1 zlDkKQt%_gPBM}G~~4yR8aW8?1tRu}RlC2p%{xL?OIZyo!1y|4-Q7>#9y&z$w_7qyQ}=ft<#{t|JO zLoN{9S$nCBknNz=<2N;2)76a<_HDt#_iCXobVhzH;K=0vP`yq#b9MjCEZol$=~sM;5Ek}^M>O6 z{GgLD`lH$}KTyyjKs79zNpxyqrSx%+!ieOx3rFBSs|UL#wD`C_1_r` z*}pbq+GwG#Rdqgjo-^e(PG$gY_Y_hvpk zz0_)*n?Ma27p}Y+4@G~wl_W_nKq79QHE2-fl-aXmX5`IZjN~$_*xcd6Cs#$Kdem+pd>wSVVybtyps_WxW<|^%;uh?se9pyr#$@S)Fmp_gREm`5&)4I5Er0%R zI&QYJ!}CHLJ0oQT}uN4%TiM2x!T4TSUlcuFUFU3wX*IMdRnj}hDJnuVq41rIF#j|)0rw&?r*%(JDIB=+i^$8;jEBeGI z8}-s>3vYa~P#8PC@383nIC$>*vTw13h>5?goQ1ugfGBaC8~px`_`28?^#s&v$VDA~ z2PwhtKPk@%pQ>L$|DAjf{v-Y<{ETx(y72DFvcD<58+<|A*-djA5#OB!m=_2!ZrQOD-+cUGT zol({)rN%%1i~RuolcAgJ2eyairM7OJF(WAGt4G$5=TnoC;?aE4jEvT;Q|B47 zq4rF%bhnNepH<-E>{9|?BWvq^X>F~5yN&v@f_y8mv87qvRD*m%I&M;BSEGrvSaRFC zlh`31SwWl!BQwb0!h%;NQ^RYZ4-6Wzgp}4{k5p9Z)TWz|#`lVy5jbnM`pU_?& zY+I2|sO-2&F}SkEwmU;n{-4`clHh@*$gS?KKK9b;yXwzuF47`aBCbMf-DIXs6t;0n7(9O{#}j0O}5dJ#Ia(~PgB_#tqg4-$hopv$s@fMK60c_;Wkl3iX5`_ z#*M8v#52U|Ezp{Bw`3R+M*#INJzdWXc zZZKPgYDi;9|XkN@^!KFl1-n0<||jd)jvk^DL3purQ;qc7ej z?x-Tho>=b8NZKxZa9=v|JHLx1bg%MsT_r!cT45_Im~#E^V~Z7K^i&9t3dh}UFCBf?d35+83y-} zetvOrt=o7x1+0lZ%5`!sMs>sn#NL=madKTSE@ zz}&0exm?A(?p2Z>l;^4MRo;W~kum%CCj0jY`HULuw@PJaB}+!7W_3t9p`bNN%gRc$^Q%1m z-T`@hrG|Tlwwl*tCzYM|4zT10>H(%mv?p4#t*lhvyLX@xbSZrR8KK_j<7LF$6P>Q* zE=rFEk_ny@&;IJq@?D}^vZdhr&#>p65YMy4v%UwS{y6chuYWwx5p<>R9pI^!TDewI zk!n|LH(2>dA&1CUUF0FQ8pGYqfJHLAqFyn&LSBIs2wdnq7c?1qTykX!Hd&K&+yjh* z<%lb&*NLD0(V3b`a$KS;ZjNh7eqM>k9M|0&H|#d{?%%g>|MeR-VDHlTHsJ9=Vv8@N z&s8>(KoTucJCKsu<;zC%C4hkOW*V}Tjl}0gMq9|q>hDUr@w`}hcF6=gitr_YeF-bC z?`;zcPE6k1J;878FzXQG`5J@4+PZsK!DPR9pOoUzr2*8gzFz=Ov(S-j=MR9(Bt=@G zADvL8<4%%EQJKNS6ekMvf5}1_xWtf=eT39L`j!1_ZdA!`NB>$$;scwDEgtPR&C7Vg zr5uiVtTEPzy^S{Lno460@4-%Lu>7pdHr61{#3l*D#-6&VAsKH0F6n*D_Xfx~1edtG z7zQ5)w(RoCzYrU<>PvfMo7?>w=((rn1=$yQvIq?6kq(g8wM6ByMj(#^_&Jd5CvB%>542 zVr1-+jVY>LhYS&rM&!Y$V>@z~{h-$=HLOsIk;{`LBRYbQkUxS)>JOF1?<%<;+IUK? zS7Ox};*8$TUZbKx{qQxx=ER<4N{e0LZ2fFP-Y z_Nquy4I1rrO{v2w?00)MLo}%6L*&o2`gC!nQKd|&Jx)O;FC)lg#b*5i61tNaj*;GJ zh(q7rRwwWX2NnTVW6)W|6)Y7Q$rZ*Zk2S=K^$~1!H_BhAl9OR1y@EB1?BpczQL-R< z4I6y~vtGEsDlc4k|H6d}cwgtYLT+sNk{kT>NK(9X$$Tk6ddbt-*ICgY)!&WLkFXlr;mVEC?&$8 zEU4l?R$bw>XU>qaz@&G02UTe(5FYlxp^}`E1R*Ic$Cu^pXVVZ%3=2{mI(zPyv zwb}bZUu>o>B7Iv2%tJGcaEhi7VlU)@%HD?b|DC}}{MWImlE zYXYybx7q&5gX}LszQ;R98d4zNulTFTO%chFsfqq7 zuoEfonF`0^KNikr^|!wNhSkqr#Q$Y{A<%!_ubqQ}I{&&3r{c_R;}bLlk56`|>#3<~ z8T*~%G75cv8++Y1@Xi8FL@E*9@;CUtH}_z_gO7&byL%1$$X^|btZ>op#N>O+3brKq z@F6c(?;}wW$iw@-a$EpWVHW_UjJWI&Qc{wd6&i`V{S2fs7K{EAH;YN zqsa(QD|+6KXT*%aGrqy|H9S*}UZa9-2C}kVAD@sL_Lvf<#+%H4+)9v+8IH--YTTV$ z@dm4zMH*C0jZu*!S)>XIFyFa@U#B~f&dd-7`Ll+f;-{1q_vf*<|Ey8x-CtRQ5DcQf zH_#u&jG`D_)c;OAZxqkiIPqMC=icHu1}`+_B~UWS2z0lwi2sASuqd zBNYlmc0a49sXB0LFsqgi2fHI@4RWwkN*MePB`qb)pCa6A5pTS_9X>1Zd*uNE~MX zBasH9p%Ev}q;IEa5up_?-a$m!KF>QUf7X8?|7bg1gMc-%RfjPSeNs$6*tP{sI&I^* zvqoF^ei&fV?pkD9y~7g?uEEYxQiw-TV7o*g^Fx90fU@)TJLYr9h~D`eGSmTJpQwkb zS%B1{I;he;B)Zz!?BY@F9#`M_Iz(jLZWjLnk-~)3?9K+A(WgPlgR6#qZzHP7e zBNvp9JiLi}ZaO@&ynNK5P3*T#{bRa!kLiE0f7>2C+8SbJdl#1e_+#lX@3NYjGVfvZ zxzKwy=H)4K+a9}i_h@Ujy)CEV^X^?e+F}mCdDK&4{GG%cKuZ_nZG}7Np2iT9hno~) zX%!d};N6PSz~h?vxq6%o(iq)w9mLJs-BN9A6;Nr8yOoIX)A(Rn2k3ePQitm(qJ%tP zFUsrYHB_Ttv(HFHI;e@ z4G=*m;6fs{eJjao^_N3}JS;POLuLed&h(w;I$fF>G|ezM6iXV3p>LV-qZt#dZUKKe z{X4|VLt%fLrMS*N`zPN0IUdScl#JL)6!ySJMv(2WlvFQ~wo3N(@$&cWi`e)q^w-~6 z7-Hk|1jNSQz8$gg53XRLClSPI8gk3Mb&`Kck?~odFK$!no!ejVmk}8sxE1T(Gyu`) zP5|s#;J7!MXslT|_&4fjHGHdX5q$gKfu->SGxLPFh zcI^+3>XO|zJ8yaK37tmoyZn%IM4Qlpsl|iaSYn5_Uw?k)?1k%}l%2o5!`QT{m#9KJ4A=@CO=svD_GB7$>&utwJz6EO%@=j}kb`V=L5||R!;8wy@ z!;`^vTws~P$Z7~Ny{6Tm-`P{MS-^T*b<;YlF%4@gK||kaFFa6sdJ%-v?RuMXcY$b4zpb`}H@pi-=5V*H%tqH`pV`kMogy7@t7> z2pWZtqPG-lb&(Ob+1=Ubn&pG#nOJ`(!RqPkq2Q9SagF7a+ZlG&MT)!Cn9tqO^FRxX zqy`;FuJqMNm42Y~xo73t`+L-qW?72#yN8DBu!C7JwhmTTXUWUAhl`U}P==m1J~6@S z;an?utO>x)L9ZPF+d?GDGI`E?r}h`=G|pI*A~QBQOr7vkG&J5+)Z_G#e4s2fW%gc+ z3yUT>#dgtXrOS#|{^R%JCgWYD^H(dkZCm+O-Hod4+pE-cK8LU6tN1*&lFeqN4BIZ# z)+p%BQ)&s93(4r|j$E#n>Mtc&P42bQ86=n&e!}3TO?I4UDE{)f@Ya)uPCJ%6kiD;# z*kU%uA{NA`4{<#L(~5b%gEf9cEkW>}dt#m;ajGkfzNGu&$^u=G!0L`j@mJ*~vU(P& zcov>zKlY8=o{+`743FH~p>(c4rzW0X#CFRjYVRx`tnOAxrkx|&gT+(r2Dp7B2|^s@ z%t%WGLx7DzJH2KXc+GhhHg`;aRSpQAc%o-)+seb`xKA;7!NJATQ^w3$I&{Iz0q0)4 zMW$2G$6nAO#oCGbFLa0m3%Kt?`(dcX$Kb2_dnuMCf(-3odyKJc{@wNW6kpqF*=&0g zX}}(&N_O+R>8+XiMlJ~R^V7~XQP=rt8k>Gk6=Ta4u;es+LSxlqr3yDQ`>k_$^}$AI ziO5kC)+VHRwlhWajhr!@4?ebDEvd8R^v*P}Rn0(eqr%c;i&$a{&f(R+VWIRjNSwj>ioER-Ui^x$$oPo;A zzAGz3PRniWj!#|6ZmnFtV%4e@%U7!9Z1*nygC0fkZRI@cykeK_*heDb;-_LA=Bkl^ z2NM22t#`nQ$Z!tvmE=23SZ>vk*YnRD11l93|0j~uDG#Y0Q|ZdoX*yq=1bn(*3 zTDo|dd#GOiVj*I|9rXzEH^b21A;IcuTH_;m)CQgL(N|+4EkSs#+gT~j{rt%FE}F!1 z_*{hf$|F~1_1>^%?S_M$KYyos<~5|$Ed5PZlxK1VUA_9*XOI28xV`UQe*4xlixm9PE%*Cr?D(Iiu7<$|NB((!T47J6&|gOTMiw zzFht|1vI#%tv#>WTHDuj+==$Z9*Z#(U!^-0j*BCbjy)C7GOcO3Z0oR2o=zcHBU$a+ zRxIcDaP^YC&(?>x-g$KPD`P9>EFD%}y8Y(G516*T#ac%nveX}Y)pB(_{Oa0B4_n<$ zIQLbIA%4*jUMp?TSb?{p7}H#B?HO>+$rP~(hx&Vi$#{!-2$g?c$NznrmAxFd z6WmJbzMi?9=BsPtb|qx-hI?$j?IXpReS_VZFO%EV|G`5R?$+jHDcT-@wu3Mym=U^_ ztU1~UHyL^&sTAifnHhtRFPXRg<@NKH93PyK`SKb+YyN)3FPQuB#+8guV;kAZjUUUE zwnh8%t$xafG~Zd!&FTI*_!sknjRdCaXgWTJqdiV?EI6hnBCsTpdn-Ohn-$f0X=1+< zc}skKDhf{YOI&(tA@gcu9TFZ`6Bs_k+Qy45R7?0@w$tUu$Mx?$>3F%^l{q0=)XlFl zHp=p}TsDud%$+978#BJb=I#wXrptR2t60c;WUUZ;fuKd$WpsJ3v0U&yk`Kv`91=k@ z`B0Q=@}a$4j8T-snq#jIt#NC^_o{4c4LeI9`My(57ZM#!Mgu9Tt#RdC#!^L|I@~hx z(hvcc1GfR2TC_U2u1^a4i7j|-79yShR5sSdxnjlpEIToXuj~G+F*Wz;7gO_<>0QgK zo-`Vso^QLyt8Th^o*`f;{@+FrWLR`3Q!jr1{_@6XbSt}j zpfhGvglA!Lva`}dl9_2kN|!1`B} z?tX|5aC{Y{5X?~r;OB9y6?d|?u`r`aMhv4Q(1-%=?(Y=|dWi@{mM@|GK4v=|84t{!HbYzl0$#l zR#%5EF(=7(;E zR$*OADhp#;tm{yiyYOz9ciRUFqb@)GJWF#4{dMQ)$^737hHmUJc-exB&yJsbql+c{ z=QYzOGiQfF+l{f=!}jbU_+)7o<_7slz{^23Qj^Vz5pQbBEN!wVRl519K{`63oUBg^ zieF-Tx#m3 zAat2s6-lT&P*Q#u(K*UTG$|eRE_@2x)MAbZ2Ek&r=p0+&B0;!b4Oy-~=!|#)_HF^a zCKfuV7Wz(tYt8bvpJtCbw0QndyLu7Y;fE*6pIFTj*&~LSIgj(plsJ8Ga}DF-Znld} zy?nR^{p~=1Z7{dgUl=+hot1v*tkkhbM9)e~ZNtzT0Wqu%UAekn^qwp z;=Bi8ftQ+IywJ*43 z#=vR(?e(_I$DS_r_1o7ftltQXx1^z7T@3tUb;B1(p}oZy=uGoQYCPgH*ss~wQx&%# zqJz3Ey*+S*_ja4{p#E81$qU&+Tf36BlOtZu%B^Le@{RHa{RwR^!?>~$Q^X|n1cZ4> zQq*kzZQWP4C>B`vl`_44gM41ewiTgn7{xRZruF2^Vne*-S3g5P+Zwr#OZNG(1{3bs|7LrYr}3k# zKfA#GRrqk$kGAu23X>0))F#8+&ZMDy1LT9bk{^vd0u4h(K`7rbzE*WD)uC_-`{T>EIUxbl96EcwTNund-9=0VaxV?{1(sQU-Bwed{?8}les|&M0v}o=?+`2^DG@Qb1(|_K_|kSl$_cwu@>W`S8f%^5K^($b z*dmCvYzY>DLVmrekbm8hZ3BAXZ8p&TT%q9kbV*c-@VwPE$jdg3+ zBYdS$SSCpH1;^4ev3g+ z{!Mk2Gi;~jZj}Ak`jI^^urlMzX=~R`|DuLptz5fy1$+1b%Q*5;K`EW(pw-fD&=PPj!xr96j;nu_L_Xr)`B^BgVd5k=^&<@ss!;bdQ(0Ju>y7 zXypZWmlmUkKfB@C;iFpwKI7%LbEo{!&YgZv@DKrw+55vj?j3Kx(+!pw7LFL>n$Unt z^kF(Ed!rwk`UrEQ*7+Zk#y{LQyMlVR70ORj?-NHyDla_c=7c_MAEOViX963$cF}PC zHr5;r_Q35Pfon0>##VTKO+2s0_!A7j;u+E<;Dgni?D@jqJ`7fFtUas(OT-X((aVUj z>-h@5yN&;O0@3fw*>ao%MDr51=iVpu?jo$&hruf`Qtz-J@vedZ?GcMu(4}`+(DARf zeSI8qC*HfiM>!(i+eiCG9^M;_IS3G379L=5Xb~D%6B&Zdc{PzBn{#}^gsDrf+R2dJ z?4*+)KR?Ek=<;9rkj4e&@Of7a4cuWRM65(FM!lPFAdA8t< zbLZX|Qqvca_>oFBlb_``3-_kH+r`S_v4147cx#t;+qB{1V4&T=CxTalw(a#d?O0p<_1Na``nD0vI?@+GUb<@eNOXWE8JjL50ANVy9lZnWM z0<>sUD`Y_uYr@DhPCvpkpRNiKzllzky9{u5TR&ssjEVWNemyVVRTlE@k@4Xk)-5gk z_7r%y=1rRL??D!R(;{!V$o5pPYwH_4{5d|&(7vX|_OG@97UxJ8d9b^A`YoQtzne2l zmT6qq0Dq~TPph|pv#+2d9S@k({_t(6_B$MCIBGniR6ALYnvZx_du(;u7U(beC0dLL zuJM6%alJkf>M>c#$V74XXLJ3}hyA?!99E=0IR!`kB&+P7J~W>B;f5=*MQxfAakUSp zX}EOCiq+R%J-K!JA=o6(Qoe*k+aEu5>M4J@RNiunfAr|PxyX_^4L{p*-+dIJc^hf~ zramuy#raXHc&7E@c#bBXg}jS%L5oS3cb$$gFHgx7lOW!ig8OoaK@S^Gdo(IH{Dd~% z#2PXQ4IOi2hN6j+i9|&6r+7w)@oS90oe-};2FQm!Ir z>zKzDncEJ0#e08^DDwQg?cYD|ThE?k`D6~pnjt-a`fw8VYoY_X8is5LSg>$S#V^f1 z#kLh)%pKu-g3mf}f~`K`dvwk?bhUrok~LdwZR9uYS=ej`W{m#f`qxBbXq#vZeTZWg zM_SShrlf#j{}oO`Y*8~Jy68Y(hV~B-P5^tS8C_{}P=)^9)@dk6(9l3_ZcyGV7o762 zD96#dx>)28J0n)oFf>E_r;4AVGh4`?5{563K6M zM~B=pWT;cfe|Q!4-xi3r?v5ADA)a0#?uHPjAb6Zz$9(~Dkmzcu_NZhnoT?R*A?{M* zokSde#zzW=X`-e?ZxCvj31X%qLoi7SQ`6?v)W1=a9UmQ{48F*_1qZptu`4y)hjjyP z??Aqi5G3LK8h-5tR^!cJCkRwDF2U=>I>DJc#sy7ZJp=f>rMXsDCsOF0SqOr+ny+`R z@BA8}*6P;H$sj8hMLOo`VvOqy15%=YhxmSj3arjfkM`d@=Nupg9Ve>gD@%q)j}G`f^wgSS6xdtSfcH=@l+FvLwg> zFJbA$4Ojv|`oH0j5ezpj7SYWr@?y`?XW? zL+UvyM4mq!QLyDQ|K8&9|mtX@XB(#1)wc6AMLQbUYNhy-U0 zohiWw;}T58c0NwbD2Mp?3V84cHhz`Z4dG9tp&n?H?i!onD!^PS-94N`T+v{>4@l|5 zJMiy7gK#_a#(ENG9BKHV$8oN@ICaXb`GprR&fdE49bu;8!TAYz@q?o&uM;=$V~3qq z3zIrG^5;0KJJzFXh_flgfM&5Mso8qLon4I1a-}O;_Mn}H93VOiv^2JkadZ}~H{pg7 z&)D%JlU7GQFxc08rM6gQiC!L3h_kC7E&aqeTKjGu)lP@~Tx#7brD|up4^E_mRDtsZ zktAG=V85(dyK~o?RTubu_U@|tB(~h!ziIjM&9*j%m>NhdpMUl>Xu2!v%{e9E73IML^{mWvnv5z^%8sJpzCRMvsI{Uga6JjYPTGA!A z5SJuBPzO%Rv~Bzr2nE|-qbNoF>V_V+{s$WL4;L={aKB>l;>C?4Mu#(IeEu0iont=j zGH;NS4R0c6x5U5%Z@DFQGaU4gr<1>PwcFvA%2D}V3pq?YmWigIF`6*UjAL zu)&#xUS~H==r!0Aij!stTd!s^fKdX1J-d2n`__}MmW(jiD&^9U%uy#_d3^gJ)^g7i zPwZ|9QFqhkZ)=#($j2XjH}}$ITlmF`U;~}OAGbjNafOYvx3zVEzo&<4_EW0OTOsdk z3vK}@Ln?!%5bsb!NT7QQw~*jgW>Ct9iFeGnd^@nVG!h`uPuBGsK?E zn(T^REU5*gT}`W!6^Mz53-j)XNs~s-5b$9VWn92}Kf|Tg)>~H>%u7sjbk{VpQxv15? zhH6Wtw=-=X6bK74!^^&rE`E{D&Mqc1Ly)8BSLB)lGnJNvTTbXTA&Tt zjNBAv7+wHkD1#=aBhxz-!8OQz3qLq#@+W5xY(dI$gtfo5VGV0(dwlK}UyzHyeFI}A zgY46~@R{yxO_|=%qL0tW!_d>`>oy6LghQh`7$3TkMOO$KMTQ)hhyyg7`CTARY~T*kNNk8 zuoeIVG$V363!3ST0w#3=o~tpQX7aG{pXK2*|0xgqlRWJIe?cC`*{EF}#uW@E`yP-Q z-u#6rM^BGGF#hyWru_1z)BrI78aAi@}&w4995jhdyDF%-@^L-w%bX zj_mg|+}}fZ6@B4;c@*6*hvj4%AfWO)fWgsk1t&xT zCW{nqby9I7$7pfIK|Res0c3!Wj9aZM0fb#iNa10=KC)2@CgGLBoE1wQ9}!f2A}u1X z*jFuqRqMi^uktJ3Z=KBoUZ75qGaY^Gz_{I{0ao8`E+*MYk(oX&1hs z|KYQfEg!wVNB)MlVmEDc7}JPY4vcMK&Gq@X!FnMU71bRZMkmNN?>JzBs*J(==Q%7^8 z+oHio2Z?9hR*dH?fzO-3rwRC^KHMdx)^G+1FQGXyC-e1sanmcVzP_`z@?i^;->c(q zD^b*ia$zeifAk^p;R=7F;V4j~(Xc;0g7Xzk{vK_$wDj_Jckv4}8{HKz7n9`fAc6Pk zM6?0XdyU!sR14!8Khw5=vmQG_;dxH(4fGq&8l~|6Dtimj8^$XVxJeZCBmNE@)EnV% zAoj>kb0Bn3V&?JVr`oYvc&X50zqm8Tl zPd{F2sHlH7aPOagZqvp|`{i;m&O(8^1>k$dz@4B0XTurHf31R0NKQrjX=~VgowsQ+2uuQb&Pjg(3a{{O-^mT<>VQLD99ATB8d) zo;KpJ?{y{oU++-A1vZHGpd+JuV{>M$ zIZgJ)ctmfWj6`oZB{ypvc!^NM>tjU+8z`W!zzSi8_s2d%{Du5BNbYU}x!VhJx3QVr z?dnwPL1OnAsa6xan@gbN#-kP^#X#;hO3q%sX4U9UQ8Vmvw~Je?8A$Xvl22tmOYHJIrXX13*hZYtV+Umg#?48Sk$E1t#dPC3fcdB(moYFJS-kQwq zg&;mg7eO1)#QvMeZ69v=UyCaiSNsJAFTMBEw;ydAI;^?kg$H%lL{Vo@$7S0bs}lo z#YvO4wIcxtSoUL>rgH&0rinV+_3@H}#eN@`b!r-^e=O-SF2?U%6KujNtx%88|S>1%J?PQU> zNYuVgO1gunUF&P8wVZiC)b@Ar^KT|zpgzBlFmlA@yt6mwrp0Ik5fy9teOPz_*3GWSj!ulgYHNOWnUR34Sih4W}E+ zCq}#oTr&}ybTIgOE1XAZkkwlU@#jiHNvc~0NPv4CiFE(BIdS?~`Wy}p5a%BO z8gWL#?+XW#j;Sgk{zvKumZ@oKq?V+4lY=K^QBN;9(Ds${Ad#cF15z`SE4)29<@7;S zY{Q{3l$DwG#;c%DqmW5q$;0yzjIRg9y&~yY#rDRKO}gbENl(rQ%n0d`bbIEPFv6-dLu#;dzj)v zt)sntuky_Y4zS4ww!L(WSIaUr)Fjyu-2mnepc@EI57G@9(-s|(ubpP#C$9O7I}*&z zTXfDqp5sI*0(V0G6tpr!qm_7#el>ZO=o*qL(X~}87jlY&96KKv6|{xDi)3ln=I0z| zNf_pPph3_+gsTHzG2k3?5Q_1TEyP4wpUJ>M=TR19Vnz~T6-h6^=ny{uijr>H(XBfC zAWS@l3v9;zP0VF8oBtu1cGQ9UZrsrEF7`Lz$wDWoO_%};H&ZSRZ}dbKoRGij*t0xe z+qHP_I&C9UE^ng6wTZt&_(xF2cMFaU1Gu0e-A3$XWFy71E@#4Ah#A5BXlITT`3rKU zV!#;)LVF|_aV{bZ$Cn@p{Bh?Jor#F>%h%-Jm1pQ&geCIU;%Edc59?O>-LRc-Vs$fU z%A*O|BgDu%*Qteiv>^0H*e*zeOh3+)1N8-J3G1le50&zOSKL{Ig-eS(2~2{)fH3lw z&_RqGVf*~z66HJgQw@K$MwokXMvi_-XT>|H3a&)2&@W?4mdL-_-eP-jF#bmkJ5$H+ z)^Im5UOrazL%tAbUc5n;DLUBI<28s=V7B)n^~=&u%$PQQ?5+M8E7H>zEYME)YIxS1 znLoqX>5m2TYx?y&!@{4~jpo4nhp4%L2foDiwv#BzJoywgwGEq-(4uW`-D8H{xw!*h zdi~(ku&Ahn73^Cc2={dUZm)sg@ZUv%(X>s>sV1}yrV4ZA2^%M!@xY&mY~u`Tk-Tlm z_-a=&J@xYy?bPLN$C@B$|nkrL=%>1ww58Mt@*PNehuZVLp`OZFD9S)Sn%a7Y= z9;7=M3v|e#;nu^SRb}8a!KoyXB48zX{zdeMHPHN>M-Q;=>{niQ00b}8%&qmQ#F>G2 z#Lyr=6~g-%!g~RAkMgr9hYU#N;r zCTluRXA%ryLa%(V{(CfjXpsDEfp_JFBiIqqZ`0XvXYu}UtfMlF$%%M@eyeNvSy(pv z;C9PvV9A@6$@h=wp*GN;{yxQr)arx(67L{h9C?jRW|KbQVa$c!y~zJ!IPT0x2-Akt{3og+L2zw%^d-` zS}^uQ1AJO$eaimeIiDcj*MLuWSB-L(+8$N>(oR!5%Dpw` zym%cyewEenX_t^?Ci-1IO`wsz&NJoSasZ#iw%ER-cGiF+$S>{GjM!Dz!ZTV8Zf3*BKw&s09Pn0wM6rNLs)0cHpUgO>asA7s0WX(1@Z;(^f)OY) z{(~PcvakH zN{9}H$fWijKkjR>jp*!SJpX;Z*goVDcDE70O84(b9zi<>$8Dpjofh^TLuVyE`bHtU zH*pit0BDkEAQbRe$g=H88GUe{1<=r;9T~kvx;Mb5EQm;o(`MgoutpNTSr;!}t&v+d zP5doz$38kyu=)4ekavQB_bZib796z=LEUoA{( zjd)}?Z!uT?Cy93N+}{l;>m%%=Z$i*ogyb>a~IFe@Mvw(EjkA@Ym4b z_9EU24M3D@dYG`UdQkafy}U_o8z}1OIoTn{;m!!!6W=@DNmj55Q7-Dy9TFYB3wnFn znsm6^tYB55zP2Wt>Wejra*`9%wDuc*5q?D2wNb9!Z5H)^BY4H0jq(-^x73$u{A`}6 zr{^5P?UQuzyc+n)GR2#tT;3$PoV<@jxscZp!!?RxxT1WTUar-5gcon1A5Fe*g4bT( zj*lqBRCSzBw~!z&F`q$;LgIrmLqdb%LZl$i5c_-zd05=JnWgDq=-=mO0~PZ`kWQz|*|`B+St{F&E9+r~51N zMp16BUxoI2G^4>{4StjdIkdl!-~q3=2A)JRzH^ftfxtz3Aw`g=t;rBqYeZeh(q9SL zzIk1eph&P68y`ev)WvwZqQ9xl;25Qi6Xg>e;8;RUqrRYR^3!Fx;#ogmflhQ^JkR34 z(;W}&Z<=3e749vxQs>}#u=pOWs8_^V@7VM#Y{P^xMQWq1edz06glFdt9W=Zz_s)KyKljBwCickm zhZiTNE$cOPOK9}+kvpGy>-4PA#p%m3vX^x(To4(yZ0HLc<$b+}%@{gzIiHbSy}WW) z%zDp=@FzDUB^_)NlRF?M=it8Qjuy1QB5teD~((Naf2>6-(?m2lKQT9X;!4G?f zmUjvx(L>scPr}Jt_+E?ieWPNY)7ARNm4SuBCydV@(tp+F-o01ue`4!_VTI3+E-cI* zIjnF9U%hIxYz*vbEncx3p|PI{a(5fjw@XaB4O0h>N=f#zgg+nb;ZZnz|CG(pw~z1~ zwTC(eG~*7c5&AVLc@(Elxy#$|O}N*&3DLi9*43#n8LY2AWqb8|%z+2y-~?=gF4##^ zAs71SS5vz%x=bT7(3_)hXI@N;<0N>Qamio16BuPVEawbC!oFc+b92Uz%gL!9%zhj_ zJ!ffLr$_sa+7zE$G5FP*npcNb#6>R2e{lo5>>A~~ab?x+7}@W@FZ}Zto{?KT!{-ft zYC}rW!I(DPyY=YG@7Ol*I~iRwy4rDFCC7<-K2T1*&0e_D6QS8es^})q*$r#gY``IN zh<0=5qfbBmh~}pfW9ucy!77ayljOahB;0UP)LwUato(W=(_3FjU=$=rDvjAHRaR zy}zA>F6+T-dn_|7;CZrV{mD;1Ma@6)&UL)wN!UY1L0_l_A{JQ$qWk(Qh?e`_)iY;q z@|w@BWlZkB=#1gUh`&bgD&c{@7Eo=*cdbA78rk@oD+*wJ)DogDZ^RUb^lj#Zmh$gC)LIe*@E_uM&*(>8y^2ziCpelcJ#MSTl8)8m|y z=Qi?LfNQYg4)ePW>-8&}wtPpIIr6Dx?b{EU$vzxmySy9Gbp?DBANsXM_=LYKX*bNP zg00)kA7k^k^GhWJsi6xv>i9xumurLgYbPV zz9*hQi5W=fru!l+sOG7CHM0(sJUa`GA^=MLN%?EuiygPYN`?120HC@f5Is96me!U?~GtlKu#sK-p#fX$Aj;$S4RA@Tgu_ z;A8{pVFt*~=HutD1&M}CK#xYaz|a;Hi<*m^TzvYcruFl6F;%o~*LG6(Zj;)!Ypr|^ zOU~O}l0CxkpGR_MIo)QfnA|!nG&C$i2;@w<1z3JUAGEJHCg8cXVA!PPQ-&>AJGWxd zJk0J;m=7}K16U8gAzOhAI$Hxe3&GlN1L*9th4q*QG8b?mKn{{*#nN~7eKUl~&qa+L zo84o?R903NHGSaZirw3GvcW~2=5_2kJFQ?rRDh3iEi*GcbM|=u7{0wIJ!Nv?_$lUo zJwjTJ^Yx334Td20VBd{GlgZZvZtEZ*Y1q;Qq*x|L{Xh2ofxT}wmiitx;XnHBg>kRK zxXq-=A|r#tXu+FQvBA>LtoW6cwJgc3*tDr4b0mLr$lyT*1%n2wrw7>9KO7f-Xvek} z;-CC=e)-Sk*d_0y&5zLLf69S|MmaE9mkjNwbQq@SvzZ*2B5!Losb6|>$2fi=eri0w zz*3ntD{)|G#Gv*)i+utIcNsNq;k-T>ogxNDCk%?}Fd)EZaQc+ts(+iL%*52bH(KWP z?Oza(cqIG!WvV$}i0v|@&>4|YAM}-?9 zxhi((h&*WzRLnyT@1Uq=MA3XqWqGmjGNvnbZkJti`%yz-8*&Ih*9~3hvsd=py((tYO$@;GA5%PW=9G-m z_%1V3_qM{tt$Fa}ie>;>0_UI^@)vui9)!7zY-cVc3P8B`%Nv+CY}k;Tx3_ML zpOBm}CZ=de@Q9uZHf>taqd25Y8TZ}Xx!=uivv#AW=h(o&!cm5-l%y9oZ#op82zv?U ztq-eFDh(D*Z(xuBNYn+vlHQQdKfWzz-hSz&(o%W19Fdd5+w+r4@fz@x4!*e!bWgGm z9j_SR6J|nm?DV-Tel7ojbz8^p51DIJkiT2KgAh?Y`aoyIdy#nWAm%b0585ihuA+(Z zjvsVBCa?DG7MGVbF}z)3ouB{go+l3+cyf=xNdelLhqiF0q~QcdnP426 z*rcr^RuDTnd0$=KzNC=}vBNt}nKgTIml4Pj5D@SJzwm;8AU3sy-z^M_5bbqTt_s*l z#z}_gfXtFaOTMh*4ggYKIJBTpxw_}sXZOsVKYuQ8CB~wN`?m;E9vYRR>q$!W4*uzX z)F(Q9Uf%=2^GGUa+I0YTYn=(Qle1>g4)EAx71k1#o<|H&{*j+iM&&f$00hk0po?XO z*EP+7go38L^B~0(`B7%#e|PG;WbM*PCr=t)Ka#@_W~Jp8&18dfjsOT&2prBfc!>9P z)2(K=)iz^RScb{X$J|cpHF=^^#g_B(!8zkf5F3A8acVkQUYOJ%?^51J&STPE{y|rh zkMVx&rIMkglaUql^@&|F*U7uabZzK9<<7{i~^c?|wy@32FMs%uW4P+5>FTXSQ{uX40`(5_1 ztpzyn73mFyv{D)8Wio<$+Qx`7xaukC@=`C8JhZW_u;Eu_wmj3zq_%D>12rix$fYR5 zlA?DdSt{qfRWD&LKzos5JVIDil5t7auA8)!X=!Wj zXw;tWTPoWHk%a`q7V&da)DoR$=!{y^skCD^i<-jMv#Iq{*<`+fP3M~_vK8WW^NZ`( zvy^>o!us{RTC{_JhX~czN<UcDomEDhLS_TyKFHY@4A}*CT9JxW zW3JRQEy-NZDteLm1sxoTTM1d#4d$5nR5OTDAr`3cJ z|5z4HF~gA;$X^kHiMGpQ-<1z6D1BnX`X`=P>+9#@8yoPV_m6{OzZ{5Ft>*oE81ttb0rL~(rFeQ!uY;u}CZR(skQ@fB}`+v00Um0BV!jmbb zo#RR~r_7ulapo`mAu#v={b}eJEz^a zkwjaJjROCjhP6-og^<9*z=7f3)aX3{3!7b&T!`YiTw(p0# ziY+Z7%av$U$Q$mEyRqh3d`h$?Z>0V=fg?=u+b?8|ys`&`jg1RgvhvxSSr9emKlOmD zvFIqlT!@@k|Hz+lBM>X>zw_t%UF>1Opk>w_cv}a&DRk;bIK%y58n_5|PXQcKBIM+< zGNj%7^2^({*KYsz+e=1e$xLL^cs?iR`QaA`j*)0%I&cRoskXAoC_%|cmFbJe&%mp! zLx)-N&RJ8LHHS~nf&(~Xeeg~t-qGwlO}39d5RPu!UcY_Y;0e(vCx?BY%}+1XUxoVG z{5pb1!j-SG>N|StyYEQ2QvTF|%gF(J3LAsDog&8QC8TtWPeI%kI5NU*L8NDoj&DrM zzOt-r%;}nWWi#ixg(dmU?8}twZUL?sbA7u7rE;llZGL7%%Hu6t2Vt}rM;_Y#=Nw^6 zJET``8Z#R?!sLxvSp{X&m4`??ba*Ea4`NGpq%y%8fk2twCn2h=L(8C$#$02gbn(g6 zA?Mga;ARl`Vv~JlVFi*G#27+spObwi5->i8@8i)QF-$szZbsP&|AVx+%CB4Okno7a zq!F_wCbbB(OO353Oz_QkNRt{ncG}B7A7lsYzsrwWjy6qB{h#)6jeP&#?&I}qnb^qn zIl*{gCx+~$>lKXxRij8O2W01k`6sk4Xf-&!uxLo9PFVxxjUxZ6yl^B^(=N6rt8JV! zv`MQPPFh-o848`COT2_rq-GV-2XWY)A|G!V(y`Y=ZSwP5wT($DMDDf(|FAsV#@*SQ z#SLxOJ|&g%)RvA+4-W3uV==#s{H&>zo|XF2>`l05i3i~gCG29E&$0I9&+!k+4I$jb z{;di-iV|`&07*p<9LZ_^A`}je-@O~7(_Up!0|pGp-n=P$zvz2SaC_!Y;X10&I1N?9$U?et0!j;7?3%+ ztX)uSY|x&>kl5G|!!yH&ul4LoFm&}?F?{%P_Z|dE5BDM-=MkAPXKt5B-idwW-logk zIT^4O0cUpI1YSH^zIEs$2=V2R={k;1xAf4|T@V_YOuYn`mT6s!vZ5v8Yum0>tD=X> zlasRtRHbLQ$9LPbXJ%5eH6s%_`C5fdLQcM{UQ4VU(pB3iY~=xQtr7m)DIlh8c79Tl zvtrUFGCZL}OHWTq(dXyu#5bFm(W0)IYukQFj%A$vKcS=VV*c4lm1 z`IKoH39^=&Sl)At5ba_4mfzO%p|SEFsRt|cXiwqh7bpk)7qKN6Y2qNC)b zi@kduUE6-<*s_GKp@mZmJI1T$L_3q`unl~AUOHn_h7K%mMWUi^&((AV$~2A`Xs?xj ze!ZMI?~->yRrp=c^QP^MX0evxnM?9C3uDt|Nw`e?#iT+_jqN4eWtQUX7;91POoX-NcyLbNK}9Sem-Ib5Kf47zjP9J1eG1FNWI*mL zELo|^7NE3H^M)4Wscbagr3@(;Is|?}x=~>A!o7PJj$8QDQ*zPu_pW^Q*_HQj_8!Sy zM4Xr?%HxO=b?|a=hQ1u-5yJOSEAOF~@5fpD3{wt#5->HWAE}qWjx*2#_@G6}YZIxw zr@cNOEpnkm$gk8-WPR^C*9hhG2X2kP(8>ucrq`oecokFPTfJ{!6ZrHJ@Nz6HXE zl6)nk*~4($p?Om3vDvCHmRxNt?-0yn4WoC+2gpksizx4HQIsJ`sn3jF+Vw)-;JQP zwtBg+88rFbP@W4hzACiS+o2t3p`x7H4{|8)XRnX>q_{42nr*C)a`LmZmp9fI?WgE@ zDu!c*@CMPIXukk)(I!eJ)*Iz`1LZ!LPimj$8L(l*TKzPXQ~Oj7qd&^E`c-g4*Wfv3 zudTI@at$7>9JNLH+n8ta|BON+RcZwSiYPyVa=PzgFYm9H6MpP5swDDzl43>uJ19S* zt*wSgQ9eMF(>kF1J9a#vwpJhIM>PD1c|mQx{tmsqM(<7acj)zBZdU&q+M#?&XkV0z z?GSj|gL2qU8vBI@nrL6t*XV)9t1i>aMSX|z<&E`s=&#w%2=F#f=Sdnqp=AL6DJY+&@ggxVIXXOA{U)A@+79*MTSvLWK|PK2fd|S< zWXFGFeUwiV>-gDb?XO0^Sq^lbptmpRll-x$eayO0#Q^7Ow1fCgjqNwqM|qG#`%U$C z==C+cHPzpt*VoFM>IdodHM}*|57O&v<@WlTAK%~L8i{~2+T|qe+-8%@D^jAY0AAtu zXS#=Vvl8EIMm-!~g1gMo$N2`vKg%=|Z@$tnhb;gmlLUUXc#-5shxbrAs9F7{`9N)l z`c3m;ufHDcU(xU@_;89=pG`#hQV0CP6H>IZ9(W{wHOyc0`Y2!OfZt~IH9DsH>R!G5 zE>ypX->FYEw!cGfU&Ff{o-TZc-o93DZ=Yhj^mU+*RK1<6C^y>S2Yx`O0)CD z6^FKPFQT#kG`)N&%AE|m8_S#O@6hXO_-LxXL$9xuH`Nc)>mMa3DdUv}5BRFqzE*Cp zzlo1gy9jt{ME!KV{#lddt*>O#pnt6=13o- z6xM!G-T`?3U!1)MKvc)}KfZJC-CdeeR#=d_v_*=*F3VC>P*DUF5j!Gc?=8_7V@uT7 zjYboV#u%eS4I#0-#2C|!i5h(|MNL)HUy7+OFGY7R|Ie9w@3Nr2|NDKx#oeJ1g!aQDxmJ4`!4yUt)x}L8Z0j*K-w3L70 z7Ul0KzOj4`UypSxu{C}=V~chAzzz6Y^Z=;wqDR#O-sRCRbzXD6dCC*qtG^okA?WYR zUUFQh;>Wry-RqeX2Hgl1u9R2oj1WfrM-A|wm)GbAR4bnZJWXEs5eMMqm9v*E^w+BJ z9VmalaSr(ZvaU1NlU;fFGk^yX|AmRcM&KW*l}EqsSH{;y`V*y<@_+|PW0di2RsLbM zyt3}Llz&(){~YI=hW~ZwE5*K1;F^8I=fB|#8pr0{y7$lmW*qo{AIMKfv^!Tv8J9Ia z^ZqLE0D^1%rS;FtzGU51`uTcdh=(4!#_=YhKa@*T(`zk0(pc3;Qr26|N8;sGK0=N| z4ANze=U(7RQ26*Q_$Xab+f&8~>zm(k-QAEv;K%Cr5<(54QV;Vo!MGdi+X~2e7xVxt z8v3iW!|iQazo-?jcF4}V{oAu%?Yx2Z75o2*5SrI5_CI_vMQ_74_p<-NpGspLpYN&M z{zDD4tDKQ=0>7dkV9Rqj$FKG~ocH@1r99dlrt~|W`u#7p{As`yJ5}Ldx(YuGxMHU& zaL6~uGZ%2$2d<3+tN{)udlb3(J#ei4E#+H{!%r>c6?$|;&(CUk1Ngj8wRi7lbFm+N z3@;xC_+iCvLvAwz8+$|fmzr;0zUNKKbAH~WJm+WY^61w-Y>q~M@27S_jY1FLhn4=e zD!&cn z^YT4!QeNrrjpdz?=XtHmgZ@*72*96czJs@`(gS#-G@HY{=~3p5_j&;h2l-U=8(%NZ zlK$7`JD)FJ^BARD%0oY+UApy4sX_A#^53M&zhcLG<8P6F4Zm{#;BDaZpM*t!OvT?8 z{@X3!CvO2ie+&4jTfi@P!;SBH=sA50_(c`Y`)eTjKO_yLKPJP{)cD{9|BY@?!96Nd zi9cTOlWvUKP2lGhcyq@#(@geu6YrM-zo^io zo`oX%ueajAaz?5JuJOMuT;qRRxW@msaEee!4+9`r8)%n*w*Q zX;c2Baxcvd@bd~>Hnu5$%JmuHC+@Xs_ksfFXBi_oJ?>Wg;dcyr!8QK0g=_q23)lEV z@E9*V8h_ftHTmRt_&6%`X!6+>uF7XK**SeUeynsPpSVqf_}Lczn*w(iwJCqnRnGa- z7JgoZ?`c#1lxra`Px9v7?ga%dV;w+TiR4qE=d^l1bzAsF1@+$vtfNT6GxixTlAZMKa zE%NLQ*W{V_=?y>WdYbdIE&RL!=kn}b-dmo%;i^2#z$O_u{R%y&m3edn{GtL^;siv$ za&MPMKP&cL3tZ!WTe!ymws1}U+rl;ZZwpuX-+UVDY%S*}>?F?5kGVWAZUfi&xuy-= zqaWJ9HU02N8~7o*Z9*GuJNZWT;mUib3Q2TYW!&n*XA$2$G!HT zQ~0@+yp3-I|4oqxzV3LJ_sCnD@|wIIX#+o{&PP}gt=hey!ZAA1O3r76p3`nF|9t*> z!?pR_=6+{gPt|VG;06JlhrOb##}wD&c7Ugx1~&-*=H>W0Lw3D#|Ffr@1~&-5Q#oel zdYj5|J*kyb_4Wk#iT~mFlzEPFihj|`sd@+H#1LLik#{P`=b5LR1~-T%UQQWzD#ypy zQ%-{$#12Y1th*1=xa$2#E`>8Yz!>nMw+GJKxd}Yr7Ui*z=Vo{a1JIL89DX;L~rtsNK{8ZXi;E;c!UmitE2?<@f>DA8J)z z@#oce8Sub+1PCQk7GL5H- zE+d}4>Rn#OlSBBLXjf2t+;3E0AHD^L8-#a>Zg~Vg_u=IfU+EjwSNc(f8-({bFZn&2 zJVrz1JiOHXM>@`ZA*=ov#S75$Z}<)E#1pG@oclfWT^_IX>p0FU)H%%M7?Bv2SKCn@ z+6;bJi@ai0=e*4&xR<q!mHnI;FZb4tKXUv zZ^|p0V~SjXSE}vr;T2gdybb7TX>tp%TEoE;&1P45rP}hut3P;s<=HFQ%tlTHM(Cz+ zP}9;L=7EM+lS@tq%?H&-(0JQ+uK%FoX*<_dIG0alt^>k(TSD#9jORMQAi(MdugM3V zOKXkrEib3~X3UIvc|Y}==lLP&)Un$jYej$`<1+F#)n{huC*co_Au?g|ekp4R&D*<( z53ScOdS;~9ey!mo17!PomxoWcj`Igr7-UrAkAk1(?f2g0<-OboBv}HbyuTZG|DILh z2H`w?miMB+E4j@5+^QUU!{G+uBJW2ztquBTfRD;~<}Ld~`bj*-`+EmQpta6(&_;86 zXgvGnm-TD|l-_{@kBmc^aqNmXU08^GMxE z{lMO0lU)?fxK3;zBc43R7RyU{e_GcS_volDi^h#%$Z4$AMT(FFlaTFtW7`-*hqvW> z*b=4gX8CjBH)uw^uH#`;J<5g5kFfUmiq8h{z8RwpzJ9oE=q$)oJIOQ6^KR<-UvUR@R(8lIw`pBI zr*&Mx?NV`Di%q`b9)s@L0AD|~1JOq1>ZS8%gU-KAEaccZBa--EQAg~M9n^+KwZam)Mq$q@TR!k{}H{)wR0-(TGOs_&%$}g&Vh%*$uZkcv?A$k$oTH&LJ28f zaZbcq+`&gWgUb$98QuyItMzPvZ?%zbn(A^Dy+mKX`WwBb;+h{&$culz14Y#PC(FOUOY3~;x>4dieR&@x}RR_021Nv%zqu7D& z?c$d~Q7U{ibHWD5Pqv_+Y+1+(#2cci|CDXDtf*>lA4c@>ss+CL>NVcB?R1pb8LU>`}h+s`0K(R!a~ zU(6IR&PDmZ=`siO&Xz^_Rw;J}y{cR;(e84|6I?EqEuYg~z=ainXo? zJNM=wf3J`fi}t#6&nBHpyT7Li?}~Ai`l+%AvA0l=!%}onK?PO4@5-qv z_NxlJOR5Truj+hPP*hcMO6G~HCvamOT^fp4a7cbgKK{^6K$&3oPqsgPlJSjA0q19# ztjtVT|M30Wv_sg7W2RfcZ&kielGMTK>NBcW$(XS{dySg^_?>s|-8XN3L*LQ8dW{BT z^!&Z^@7%lh&iQ-AfYH5r*N-VtK>PLqBsfR2N9*0?rK898>N$3FulbLo;Qqbh`@Kew z=72k?*#3R)_|nm%OQ{4$wSS)%KmBq3DneI+ajT`=|G{2;$)&tq*iwxI5Y*$GTslC= zk6CN~D`J8)S$spj_J6X|iwXK$yw|!lfAkva=O*IA_1$Yu_3}f~_uk{j_44=O|F2y; zZhUV)UmyQo{C~j4j$b{#e?eY#bzVV#cISYCf-1Zl!0yuCN%Pfizp{q2!5yw}Y5wB_ z1KPI_7&tJXUAusR#Hm5_ZqT5B_U+mY+PgsGqQ)!rf6SLAsa{NkE)XH_CObYq{g(V0 z5;@P6*V4Mo!tgz=W(%?!LUmhcr7?sytNx$vZmC|XQodspDL@$+tA3CHWr400ZraSB zI7GgDmT61y2TOYnz9N0`JH89TU1Da; zYS@j)twZ-wwIo+FB8evsWr(n2#9*Gl6Gvx+rk7*mhL5SMA2sRN%o*{Px?#PN-#BB) z=w=S@k;Lv7pYjPvD0vY_P3r3(>)X9Y?T{XWy1L(xWql91I-@W>J$tw_mh1!l3(~s= zf5kE|?gTwpXXW3-d06NC@quSg;KzL}>>S(w3w~tmr{Cc2wZYvRrW}>8L3u$f4`odG zJ?JG0@-QlI=9gRIGZ?Y&trG6)Rf2Z+D-#b|8pyvKuIMH2n%|KVbT+AFO``H+X;h^3hAduERX5=yqyQWL<^z z$b<9?^5sPF{mVEu#SiJ>AWyuB5-Z>!lX8z9rZ!J?=Q-S!D};rcNgxg{Q3qZZ~`YSl| z+D_;AhrcdBz#Wr^aTC)q<_A`U7W=mk@bxzi74^)wJuZ0T*CTPcjkaR+PW<`T5Jf zKJtB&j!v>=AJ4Y&es%?4??pcm13*7<#>fIu=_5b0jP;aD^jET6KMHU;MOKJB4O{d- z>Dps2dsmbNmEIDgp2X8c%BUXHQ;!GcIz44M!-PqLGCFt8tR75%U#-f>sHnJSX+=dw zM%Bn{TUFJ4>#M44*;&?h`p>)U?WescD%ZHhbyV!h(Xrv8BjX zV9LuIKD(&6sCZUQUf!EM6A}{>dY1G_gfmY3%>sW{fxm&Y2cPkaBGq%1AW7t@I&gH5 zPKqjL3AG;3XJKF!2+XJ&mH0 z{OuI^TNbWQ|9jNm_(!y(ym($bBH8&`gyN{b-916FkD`7>iKFq|j-Phd9sa>k` zH|mg%vGZeB#sr?vlYKaT)X0&e#t#}e&>$>#FIwzgzEoavw~RX7Ax9hau{b*&S8ULU z?IGT{9j!~|*$UjQV=x2<2n6VI;=FQGf|A$-YD-N)B5s^hSy?x2?%YnZ%jYkW%-XS7 z<@{>i3cmJsZT?k!P#lDu7*Q=~c-Z%Uax!hymSC1iZEy!P5wsG6Gjb%&o1(RII?w4n>Cij=D$(e_hA(a(5oqNhkf0pxpE-e$x%jBn) z$@R-HXGQGg+$)VWG(NnZ@+Nyr}hQiSdpC`Et;-R|gM!V@7y*(E6~#ocQ&HA%VMhZ~Db_-?`;gv&#jR z*HylpRjB{L$29rzu&4`NI$hsdH|qU9eT1T+Au%hz2?;&NCbB7SKi{Fk6+7z@`NN+c z5YL#T>kp=In^ZRnd98;-KSGLeN2o$zoX-2sAY3~KA3&R^vC2uwP~qRh2aFj!{M1Zb zCVCWU|D$K08anv(86SLo+mQ9^((fDJJ|UEaJ1uwIy~b$G1U;o}C+L{O9xW}sFse>I zDSs$`v}10JIP#I&;gY^FDDVi}O^g|Sq@J*Ef^ibqGdM5~$i{JeC)T)U303ZcfByN_ zcWkjVv{CNUC_mdvKFRWXQB~zG^=ar2jXBj^ixlrrM>a+%MHlMmCWg|hMKHMQ$aV` zD7Fsq&BE{0rT*ikH`^Ve*}lhzPfeNa-mkwfyLuJt zCLiD6-nF_i!QmJ_prR@%F!8~qJDXx+o=!;_G^n`D(mr+D>K#WC64;~f3H8KYrGIo! zi;+&>^8O)Z5;G?tr;S%qO=Pp>832?RfpXIS7G1L@uiZ1UzJ4S-F08#Pb9le?_pro< z#|BlUR;Cmbbt~#Nu%`R;PBTVtSl)e3mThXm&|yV&ofb{mxi-IB6#DejN@lqC+J{EA zWXl-$YW;j=wh(nvA^z2g#S0Oz;1OX!3@nxHdHei>OYW0@dr(>^ zkH-7O8(8oL{d=N(5%<&G&xZW+{!_EC2eJFZ?^ah!!W0$p6goj&e>@lGCBt) zn`fMPw`aF=sVOXuMa>B4kP#S?Y4V>2e!%kK%(MiC@sAW%P*ci##Q|fY!3c#GM$5Pd6XX7j;yjBJ#taUzbnI`pcJB}$(J?Kn zbF?KqXldt;1|LHJ?iY&-@b~i#GzR#)4jT2N!h=KF`TN$kcO(?mPJPsto*vjf!DO=} zrr1*AB0A;-$NTvB`gh9imXgvdFPZ7;+WCj3N5(|u4~Q`bwhIc5?k(RR8qvYW*e)R0 zEa!I;-q||2dU}C<*rs{oCOV7a%r^Gdl#b4Xu8x%4#JI>@TmGQT4gvnprP#!NejUOr z(FKlyixP_$Ods=~duFd&y13WvnK|LnzJ3{|WIw-n^PuiM>POxyZgM@musAX=EMmos z>bs|o9XE1x&mGry#kX%C7#`RjVOCCqyd0A9nN=X#sP<$`q zEqIp1M}qsh9iCsidFI06VewhcFRO;HnlpOP)Mpn@ajh6pHgEOx+2uAo!_O*-Ot9rx zA_S@am&&O<4#`c!>gxv{`tr#=uN+@7dv|%4&BJb6JgN6b(+&*DE-K0ziid0vJ$iD; z*T{~@CYeYpq{$LTfrc}voPzw@7xW(P-Y?#E`|WeajvXuaob#{3 zJWK#V=V%@wtv1|=w&4%p!3(A^nR}F19&$uBVX~Dn*HG$VB(oxMq`zcu3Gc4EvU>mi z)mPR{uAfymYU-G&l|_B>?_}{~@0>Ju-M#&1&g}pAhS+^)*>pDJpL=6Btd?REdw(!0 zD_y!?Bm{?8+5LOnO9rMU=?_c$;-+nr-<99nHjV64cuvw2d`?EveMBY)tOayC!3>t* zQ4_2M6F7o(z>B@7yHHuYz~8TbCfpDjpQQ+3 z_D4L=Le?*%;YbLki-SUGD4?Qfyc~SMoHSsh0PssXKTa~mI<@XWNHph?r2JVPr6hW~;VOQv-D_4RZY8LlMLUue9u@%o<< zq6#3K-{U(QV+x;&8Igbq>HdjQk}(V^87mHcA(F*uL6_2)Q=09R_YE<#1m~BAimFYO z&fI}#K04fQ!PwU>-CtVh=l<5oJ_*XH*!XX!{=$N)B@0#zsSEAkbncTUvH6dU+}p2s z!h*hzN^nuot%LuNjWOm~p^~_AL}Hx;Zx=D}=e(GL1xfg1}ci zSk01s<wuxh_PbXaI=CA~kGX$o zT%8y0Xf#BNAm$`Bp-fY}Gg`?rO)~4*$*pg!-5!cILev(%yX-G#AH@Y%?d8|Rqp#n; zwAXZMsL#E;73ry7WBOlzdH9&I;E6zaL!^5-PY_W`VhISpa=yTzkmB5>M}_BIUm!5N zx1W5}UDIzI=fmvlvC`+)(xlI?#{!20n^h;B zq1@*Z>AC`kEms`R#>hJl*=+W&=#4w>KWB%2IyhPRD+ai~M{1<2tb^?P0Lzvdt`86w zFMIlEx5DeS(gD{}dW&YzwobPQdaM#Tj#6PG0?6Xq3lvHt8?Bpw%c)pV8LrUxI~w0W-duktNNr%ZaT0@3z|Q19rL@`*JyBR=I7P;t@XPe;_$;PSlh z%6j%F8#sIV%vth9q8o8AX*=f`Wjh8RK@rKL%^94W&_WcL$HmH;y!+L9*z<_vyX%G9 zfBxf-Uw)JC7PAY|h7U_s1k^o6KpLlUpS*wJWA`e3jeA>Iry-B-9D=2l+6$Kdl3s)^ z2tr1sI64iRWJ<8Yn&QfU{s>87)ONg)=V`+-$6F3UIJ@?n_g{epB>y5GLn^H}*6UgK z`jJ;h;@^nas1+-sgat8?D^^5C%9nl?8GD?KMl#LEdPaea}CX3?IVT$ruU_j`A zGl?gb1AR$gn|P#qLBWLN?nCB3@mWT_<0*OV?xH&;1j|nf-9NfGu9N#W)*;kn3cbgf z)VCthZEIpnwq|8#o|eBB`bR8Z4Atpz+uj+|NqAggrJ1vkbsO9%gC;-mQGgoREKLBt zMo8SG;@m)AKi~F#e!jszzCJ;|zCJyI+xv*a|KNI) zZj?|jjWT4q{%9>9!rty;x)FX}el z+bNmY7~#kp?(!O`Csf4g>sz6dMyiv1+_is?!&^M_A{{~doeZ?!37=QvGv&n5a_7(( zHeqj{LAR3g$RB%E-_&P7FGBd7SnA@iaNDuY#3f?-g(Tv_;*d~Fe5j*?-C}dlQqG^$ ze3x4>pZPBs+^weXoQ?7u@@Kntv-s@~vG_eMdr*+@Sx{cT1$W=Gpr7-re)d6wy42rU zTJsOq{lG!i>*=TE7Y>@rOeQv~%3eJnr$5L5ossgF(s;uHJnx*VJM9{RJ+H6wr=AOB zS+~RU{kj{zpX2p?4b?ZK-m-p;0rlH_-@5*d-_KR?`+>fj;5T&gYJUoEKkb(7-{gBk zs;B-J5H_Me;}-Sld!n!P_ZoeXxD)gy_5c6y8`8D**|4RpL$np_bc^u*~I4JUB2pto5j@UUg-XzY@sAGnWQQSd0Eu}i@-oUN7a6i1WSjEFye zl`Bi3#PG`_r(tFzv=-M}N>oCLX&}XDLNGYb5{(l=;vy`u9m6|@whKLWm^I7UDbj3?O35wk8Il%e z!giU0xby;RG#>M(-TfKcQGfwqI&V55;AV^=IYH#b5}qD!OUuj6uv^lC+l8Vpv6hIqkO{&UOA6$1pWU4n z5gs0GEl7_mz0?xHhy zZRoK&&30wVIul6n9KxgF9-=XW?BBF5P3+g`6&|{wT}En}D@{-y>ZLKS2@i=+c+r2BH{3FA@Bx!( ztW-Gy8pJ(_atw`!c#Ij*Poov?>B6^w5;B$dc&-VHnszYIFC`V`%E1B01HU|YN%PXf z)^RZ%&8A?Ojea3P9nBHl#$=?1p;&rSK~}6AtA)C5Ec5dX2{wmEM24C}g8cm&Qqxi# zIbHG`w$8~NLx~o?lz8zHbim?b9$qSnfXDl|>I&r{S0(65l(FeTFHfH~$7U5IrFRGo z3ro$&&h8dr?idsT3jKmj=8j$?5ZW=hv(1s$CC8DH78=^%=N}Ye4vmZmHwTCK!Vx4J znd@QDlF0qB)=a=1qb>4<8;ul}@f_7)5wiBTVWK##6?e8a$Zu=>VaQ6^Q<*9WYBSRy* zMMj22_@IQZkIBc!XcT=qhDLSl770YY27jYE%EB@+C^+8N-`_VNAk~r(6dW8HlV}aV zelmaGRNnwe^r!}=*ZU>43l0v6vnC;$uQwRLK~Yki@3Ucx)$1Rm zeLAq|^j6VnHZhY~Wa7x9qg|YK`8|o;E+oDes~-wadM*f$h|q+9geO z<@0*S&_Ah1S+CA-F?gQs++j&XlZ#B$MeO786(C>{~K) zP-%I7mzYE*IMl{=nM+e_iOC&8800U}nw9As)Vr)8*Ag8alV8|pU?uTXpty_lsMHa@ z10>eu@g791s9qk#3Tax46Co5;VQ&G~_d02VbWwda%v6UCE=90%dqFU?3U|Q1;qK5` zWl3&m5cLfWq|n?swBC#Vpl@OKk-a87Pv zEg~kvLKeArS9E#Jh>4Si)%NL`hFYZ+!$*vtIAUnO+ihLD^)6XpOOJ_&h|IJtDCym; zk2UH`%`W$*lNLMGF28{)tMgW!U|l#eOGZqD4Qp}X#=PzsHd{n^&OC+SJ|l)rnl^A$ zNgr!+a&nn?7a8PVMp^rCsxl)ZB4W}xRb6ej_ZvE5;`kB6D@v_NNohU%)DD|8am0u+ zK972^E8Gvq4g}Q?SDkQnWdR=xZT%3I(Jlpg;sG_(L+VFPI>v~Mbk*M$!c-p}<+xE! z2Khqnp=;hb$r-o3gcsn;Q#sXwNvv7OTE_|)vAa01WT4a48 z<_WAvPh`PY@%@QETJuU@u5+PQ!WyEH(?g`Y-)f0)U~dKFdLNH(0H-JN;H&Zx=Ba4& z#2~1q8u#EdDMO+0m>MNMlMP05Ql(Sn47ix&nVsHrx-KdmRFJW`+{^%XUh~XImDdVR z@^`GBz>Ojm4(5N_gG7zvKt#HoRy(RpY`E!=DXqWUZ=xs%7X(Eb?7}3ihrCK+wYdB= z@r{Rfyn{Ss+qBSQRt6tkRHP+TeDfyNh#qASl(^3g^d#X{Z8h?vNC}<_oZ{h^hF!eM z8Hl??%=rvvQ3^8C#b8y8Llx~;Si=5C!#@}Wy*MY)m3I19>s9M_e{8!DZ*y} ze4bc!BB(YuVrrrMX%xjiD3XG)fm5s6HhPQEY+{0Ueo;4#1ZoO!S|2lFErA{7^1n_LnoIbPdtF?tJ2Jc+hi5Os4NdnR93Trqz}XxjVZ1# z#924AuSzl3Xcnh<_=XA~z{4^k-^&+A`$@PNUh|6W!DitFMx}WyqO!XBQtQ6BHd6f- z9_t}RI!4ms%tVln3$hjwKwJ|8wz;}Nqh1cyn8H~CxH^s=<`8ZVZxq~CW3bt2@=&Na z;KB<7tE&eN@X)Do4BV;at#)r|i~X#&4?=YhH@_+6ilcG<0dc=j9`&Rs9K}EHL$tHN zeU?`98G^k)_yTdz0>LqhmTLFe0-Cq2>O-Sb=#Z9dymN>>sknWHT3nbRd_jO5T5o5$ z&lDiwN%f(Ja>a+K{UjwQYP9h1s9k)nZSj8-J^!2`k1JRrB)*nV_KGsOg?C(+=ZV`~6X%KXtVo^K)${P% zrasLml0Et#BQJ)yv&8s$u8HEdd9KUCJA59qB3@G&Xs`OP0T|sYh+liC(MrD_5AmLY zty{KiDYVq$@759ZvP# z<~01JHTf4lknDKlL+lK7seXbd6sX{bsiEN0qJh`0i5p*f2{_4h=tpB$?%x=k%hDZceR||?hsMG7lLTx9tvy?Jg5B|!y#ExNBUZWo5dDtJ zKf9XoRDG_ZpI?-o_q5HoAK?)UT6Qq(2IQrGamk{<<_N!!JUjArdF^R7>@*#YZQCy2 zvJXu|`(K!tUU#^))e@#F5Lz{tMi*vxc13v#OQ)*n=2elu*A=J+5L znGE|HTCjfhOL;AjzE!udPw99MVsU#pp%oS{C@ppOYlR&2w&2(9rBcwFz<=)PwxI95 ztM(KN=*P8?@( zY7?ilM!znW$y*9# z#Awiait4fN*&KPDu=TWi_vw+CH1bcUh3`*8bRoh(30dg{L0l*GhF+vq&J&*?l$gJ% zEzc9h(JraXD@gG|nM*{y8*n5kOEjK$&;VM3#cA@mulU2x#ot^%Cc3`%JgXFwufI@+ zQ`a1aCS%eew8lA@%t2{#<0|kd7dk z(w(S67r#d}_p5M`mqIgCf zg0r)OJ2aSrGqZxgcgK@e`*BsMCk0V$krjkDOJer5zZiXYT zAI;~d;;Mo9w4NBv^iR>mVn`cz?=*fiM63vonCiZrJ`HzFq1$Us;Oiz?aq1&^teTck zF{VL&+_P|wXn-Shg)i~SQI6HJPyzE^ z+=LaDW+biF@?EdPiXx@M5*jc!sU4+`o@*VW8IKzEydwRf_Jo1Q-32t4*|UU&x4MGx zC=HWsr{E*H`93M^!@}t$tam1hiD7#;5?Kh7F33Yh$j*1C3H~$Qm7RwLmkW2}$qU%M z*V4dOekT<6?qQrlg6MWva{|``{LCa`oP2B5T;|LExVMMpt&qt6kL-8^|N2LUyk+Tu z%MIB~;di$F&9NKHoZIAox*wANxy@O&aqJsJ(-G_gkJR_Yo&G6RTbrBIF0S;&(iw9mv4Gng5k-6MmS0QH>{D#- z<46x1zI}N?V)Wqg&%OM>LuF}w2Gp*sd@6l^>>qQUn!QXuy5lZ3a9nPFMz`?;hkx)i zcEXb^9frP-2CwjJz)2R4`Z_E;FCLzSvyXT<0%w|MqmPC!=Gz*!^N0k zW&=Gpqmx5;kDZNXdY0G{n3j^q-jUJKYPI(7|MI0##d&v(otqJ%h z!5xK^#FPW>4-=A0_w?>fpde}Y*gNuyN6nf(YE=Kqs+5iys9Vr|)bv^S+`lR%DkCZe z0seIZt9qv-3Mn0f?{j|`5fsB=RReolbwV?ylk|~(1A1l9^)F6Ejyp*}5{=2CDCj3+ z43HpOVo(#f0QPToU1z}8OmF0QN6zxCi&_^bp4O0sYd=&aHo z<&iDEu^00_J{i)VYo~YMuL15Z%kqg&f2f9iD5tFYcEyTsSJAuL^2*eBAB1aGP8hXx zOXCSPfZfLioM^1*clW3Xjp+G3&Hbe+!(>FXlIUha?2;#x>M){(LWBbmO2g@kP>V_3 zP6N@xAex1~p=N3$E4^S(&-uN2pvlJEJ=TQ>H{w9!eIa+$mRDrN`>@VA*L>m=3!au5 z176C$G`8spPQfADl14e9QCL|~u@sa{7&VP-6sB9MdtB--jf52U&>i&2Jm_mb=x0Bq zmwr5iMg5Rb`tcw;s1Le)P_P}+0bm9oqMER>rG)T7QU z2piJr9hfCmx_%7nI`&@9t8Z4U_=fZ9-mzW7go}-3`6C*ae9DARmo$#Z$Af~_{HJ|I z37Ai|u#g}DTN>~V${-g@xwy+G4*Zu>*oO-L>0NDk-}E>iM7XjQ{^P8`ZSsLz^B-rn z2&EZJ2aC}{8Vn6>9*gSc08D1gF{^NIXc)DTnUN3vmz042PlEpop57$C%5Dp}v$njv zbDWR-e$L-MaY+SwKhFSg5@-O}rAGIB?*Z`UKb^lJHB0owupk_qP&>O!G=+5=vx0Y& zGmqY_7}G6GNLQIB%PRAj?jgCal#kpTMqTXlIz0<4_GhBbN4i@u+^zGWWObCe?1T;3 z{$Pf}l(hsuBtG`A`$4&{ara+!#+bjpQ0Bk};OPoH{yOI~{`vr4-774R7Bl=cvi1nD z1r___ske_FjTl7Aigv=Ro@)%ER9eWfg25-#8~-uZSNPRcEhM==5x2V&1V8!0>RNHD zST$;$OW6yl8zy8(^O5WGW_bx|y&Wc5u3r&8XrwiSKkt$@qb%PE>AS3C~bZO9?;9)}gN?c)97_sHQCi2R~VSJ?cKw9Bvyt7~R)M?d(% zI=#PM@-g6OpN~-z1*2Z)uV?-^35u*@oIB@Fy!vVgc3qpSNmz_w;3bITI2$vR(aVP0tS@!pfVm_yhw_&`4_6#?VXDdPsM$m{pDDd&vOWUah4&EHoU6ah> zFBmth{_6RBe&B`0CtE4C3Dyd%w_#??P8^WHfn~eUm{;4SPfc}6$rQG|>h8)O%Lgsq zyK{Nns=Uq*)Z|U-oL5^QELbu2-YL`XxkGl3TefiO#mAp|`}TY0E?GBs;i_>YFCw0C zUz7IpcFnp>owGP9G2Ay){M>5!BGC8qjL0il0lLKS5W~2bka4M5Tn>Zt@dIIW@mzOT zZTOspbKfoL)iCk3(>f+lt0kxN?uBq9e?-^P5rca7n0zL$7Vid@^qjIdbMuIKO?ws( zyt}gd^1+MtK7y_Yx33zvV%pTZ=gv_(qHCVJt0I7ZIXEIXh$))YYnXON7nBZ`MP{v z+I_uFY;p}kn_lHic6tPt(C`Y=GyN;_KYo;Uy9S9(*Xu|pYUL7PJFA6B$jo|WaUZ__4bm%7c!vtx=tQ0^pD(2n?Rcq%|@7do)ZkiMlA z(MG?3rts+e9*t8b4<40Y*fBz=6H46mS+kNYS)F2H;?P?6k-~2Gi$B#)vlkXb$K@4F z9Ha2~9(gs^$iJ{Abu88gv@;+dXct!(${nL$=NGmvIP+@e)hvB5X9G6I;`uu##DM49 za8Lv4y5GOzzA3epcaBuw%qua(PZ`(CXqY{_r>Nib_vMxkXi(4<$qR8epC0XH!X_oW zFi1IG5gkPD2yYUxU4v75DqQ#~zvuKRH9dP4IGFOTUskSMrM~Z3kgEY5pkhqzBqLZ_93hLzHCyrZ0!c-9b{0Fxe%5JN5ET9*r6lj}9% zdv}<$Ts|j{lg|kQusorELs4&$2OqWg04S&bA5wcV6Q9wJJVPFe^21PmJ}-~M1XPaN z=X5Y|1N%_euh@qY!uqXdxVNjdW{E7|zYi5V}_nT<%zrL(;(?G|# z3cs*9BYUqFLk<)=?S4{xcwzC=U7TTYl7DU&$XF}fCQ`mItrVO*{TNxg5cFj0u=3Tt zN6rcJs~G1PxT&&ieSiDJe*R&zYx-}f5JQT(Jbry1#z_ z8yYL$AK#@2UFsx10Oz0E1UR)fU)+tciiU>7294ySU2PT@kbbq>=(;4XON;U_p2maTA9}Nz# zhY-*tjJ?^2(4M0)(p}O8I-AWzs2zR)86&PeT8C!|R$^EjWCiEO3MTR7z6rwz_i{`v z8<12xLr8Vs`Os~{zheV7^_yANySB@SUW0m9FKrk7rZijr%#;}4T3!UM29|z!LmXRhv{C$xRIY`#GYE-TMGW)tj8pJ-b^Li>jo*bS%)ZM zD16xTYLj@bRnPr>;}u~fyAETBc1;u;Nb-8#uI()NuN1HWf3vx3Wu35K((LrV<+W=C zoqPGj+2WvE)AK6G*-+h;|CIu6P8Q7(tmX4@e@8Z`f}zQG0koQd=CD|D+q@*24;Ofb zC(V;^*1KOXc?Nr@!q?C;HEs6tf*}tN@DEU=Jl2xO9+NG-ghcnFy>}2{?@EF?UH$#z zB7VyIoNo4ZR^`Ywqw}+s5h*Iqxot$rnhH=pZer}1HEfSRR|p*rhxux{ z2%D!m$u9-+fr&Wa=vqu<2gxsX@|s7R`S?I1{$JTj>&<`B?YCyFE0vrkY4iWcV0l#& z@tEfSgW$13_rROetqu9j#Nq!*RBjXqV))Hhv0L|)9lcRr#K`}#-(F+o(RmEME4_l% zH4&?Z0%o@C^2q6m#SOig)%=M7W{edCH84<9g(knD1Dc4}H= zsKkbR?i&#~w7j~qUv*rB@8@i&6xuP}Qcz$??-(k{Pke5O3ajliuy0krB(wkLa-$d) znU;D*#D3R;y8X6-?p^Hm+|s<9{dEO>tTAG-6l3jEG<<(t->$`WduC-;7ybqORCRq- zXtzM(xZOdUT5d)i%?Dxff2G0wGMD^>TeRr@s*&t8zNYIVa8E#-$L@Qc;K&s?-vd|d zvFBC0?0Lm5b06d7uJUqZ**)NXsRa)*1QMR1%~z$nfQNt2p7;8GhWjO*q$_8grIn(R zAHttv8I%$oUR8o#mA>+;_>sE0u8Vrtb)lR5i?C1r<@u&2wxzN0X7%xW5KkBJd=ea@ zV2HF5^<4+3wuXTPv8`B;f@Eit&;#bG#(T1ze7S{*-OOftE)vvWI}cVniY?%dX{(n3hNdTDZeUNi}Jb^?%&^W6f`tw^m zZe8DG$8mZwp{4$Vd!O9!-EO76h>OBlqkC^l`$|4nXa%i(6OQ9sj3%qmnsqyyb&o#ETKIpE_l0&-c(CEggoyBk2bB=Cg=L%`&m{L|m7-Aj zE+NG|87#rr^#X6#8KOC!NZ4miU8%0W7q(EWzBo;VZSVNSvpocv#8B_VWoq2XsMzD! zRfS^Y%Ovw~l!0>2=Oo8_$dPi26QZV1?^#q-RPv+zj#ScI-L z^Lpq{_Usv2lu=e&Tb5CDw#(!$T_&rfCpx2(67BLXR&S3g=_)tImGm)%bPEicRX=vl ze!26i$)i>@C@h}V77_Hu@DQi7s3!URf z77eN$o|o5az;I_l$$;U*V+R)&R;z>ac-MkEXUfmAKK=WR93a2N`c(C;L#8t!X|OGe z3>w78+QMfMo4n*yrLB8fdSqsJhBLuZ7Zo+Se{!$1G;?G-znG5P)=I+K zbP4u&m*Ti~0f=x)x?P5V_I|rU3_(5}LfW?r@Ijc<$5$Vy;|YCjN{|x7~{idrl zCfpb4q4I-sgM1OvAfC?BWK>*>rO;?(Bl>~vYoyIQUIf|g9x4=Pik1G%x(<`4vag4^ zUl-O6Uhn)tJ~bTqUE^wm0{6Uu>&Xg#wee{8d5!e$NHHHD{FyKPq|yVOjTM$tb5p8_ zGA#bfQC%e3wAghK;(~sQgr?IQz7~Psm-$F3MnT8%Bk0)z`Pu#QGehXv)sW^v(md%=yyKe0j^bXF4bf^z7KOYf z;dop6Zi*vVX`L25jzdI!4Hs~CrocA2c%m7yP0^ExS4XJsRJi>=Hf+S#`M4hb`$R%bm&&PfR$@Kg;*@V?s*#;YkT33wYK(Umpj{0?#>E zk|PQ8Fey|o>O+&zhThCRm*)w#+qP9O+#oZKz2}zaZ2L<7=sWhn!+S5Y=~=(td1Q_J z!qd;4k=JGkmu3#(^3@8b9@wl-JuoLZ^yo#BRrrOicE1gr^1E!tIJvVR04KA4C(Z;; zc{9g}1S-#+VRN(G2^!9JpwkBwV@#ReEMl?(p-Qe1p4oU6N+ws ztRIV%8!EBtCR7S(?wwV;h40I|xpy|Q*k${lVfBt5haVmH>%t>jt~UPL!TF)IgSaxa z6RP(FRqWIUr_u);BlwJMbDyacmbrWN-`(vWKNQHHunB$TO7_j1$KLttZE?=s`w#sJ zlrJ|Pu01m8>Y}3$vC$6qy?wfn{4}43d=}yPE@F8}H*=O-+#^1zrFl2_JDzw+xgxCp zY30bM0TZV4NG*+v)~{TRPna#aD#i7mQ|LO z4RmM(l=O0S(gYerL`G2vF(4p120_HANQID?7^d@xH__2fnuoDWLvAHqk|*K^-g*xw zc+e94BbNhCIplHC03Nms4ef>T?M~wxA@8eVPsj;9!lNmUsd<2LQKNPvjO)J8p9ckn zi_7*u%SJh_4m&#bH;nf=pTJ!1lY`#&{_+)v_(TQI-_=4NKY_@c5MGFZIwbIfycox) zp%P~+Vjl4jmi_*goo#jhvoO3b4{DY4DlhG;@UW`O#NC5qqlt-*f_V8uHnCE!VBgMp zOc-8T_|TI5hmPuF5$lSHDLRlBL%d9EC!fS#T4MlbXb1h2kw+$fzxe1jHpZchX*p!+ zeP!>iosSs5bp=bo5N%i#Md`Yt4T0z_7F;g8aA4B{Uq`gTSH!DXry-X&>;>5`3pqa;7w%pp zUu3(ZQyOZVTaX(j+Tq_m-EayM4cZ*#3 zGpieorGjKu;{5kTE;U^etr%trE{%z|pG<&6XQESR_zV|-&AQBd&Kx=hS#Pq5KHvZ&`C-ky6ZZ`qDdUFW2q<#+mzlrR5$dh62sybl1;!pXj=Ws&o0eRZPr_Q-P-LWk1 zRIa%G=QCRtb={l4bnEG#S^P*i3`&3QLg!ukhdwVRAU!0N@YEs6+s~x>+c@X|ETF=p*WHcGE`;KjEX@{lqcI4-k zb{@B}A-owD%9{}aZ0^gv8CIe+L$a^i1G{+?ve+Spu5J5+0ZC8zu^1r0>3-?-nzd`! zoWfJ$7gxVLs(zJFvS;nuQ*W+cyXDnYYwGGrc3RuWnhp{>@Ws*HWK{HJ`vd?1q?I98i)=M~}9RSchmI9p8Zk z%4i2xJk9_KOUgk`nmub!36ZzB;<0>Yl8;>y65KEO`Bm%|PZN1*;TscracZwP8n?J- zZMgy!enVSW^mvXACnTK6<-3i@+Mym$a-!-R+LC`{y)U^h2|cMTmVaYg!bVS9+^!^z zO?m?6^es3|YX2tOZftDa-iG0-KYM;KDw{-%tKkSGjx-&Xo)?w2gGVD@ktg~O#g9bd>-KV`qTFV!u<_;jsq zY&`FHw6Q5}I3Il*e#N=03t*Y;8R>wkV+d@0<2zF(VEERZ^vstnj`3dY#Cx}6;4`M}FdADo6cp@!Nhn!4+G{e6 zylar!(!;D}Xiu)Iiz(r4>E>aMuSK*dTX)cqdC+J-Bw=qLHWMBc4ocWFC@Px>88!mAe|6oJ>E;Kgo5c2LSZ zsJHXIif9H~64kxDB%*ZJfVB4d)kfh}AST&v4|;!xZ2Rl_=ne{*2SrcKgMNIMqyPU$ z+jjs)RcwFn%)NJ8%I;=cda`Mo1k%ffgwT@E5+D*v2t~RyK>{jGKvWO}EIa{GF?K~n ztYB}bU~kW7f9kVh|Va#nY){80{EWq|GrIj_wKzjXU?2CbLPyMGiQqLHv&Zy zs-WL%L{Wy~P@O~-q>{aI$=-+(@|2{Mg+(EIK$wL>tI+;k^4Gfp+o?+3${woQtJR7; zEKxJmiaab)t02_9ro9H-Fl%K;P&I|CW~iDWlnRTe*N0b`)I+NF{$0D|-u~KMe3mF* zg6(d$yhh#$A8$HQQ>Vk?MzBM`j)VpOV1M+L%OQVakwEhgK=(%iY)1m0!rlkgWhXv) zYQzXQ5(~%Tj!U*ub13drRaqBwB*x{yPd6ga?hhLw+U)Yq#t|dV4tW(f4#&0TQCuDL zCfBYJRU<_)KWcyEB zw+?JPOMT)x^=*SaxmV03EdRQg7(DoX>(;un8d>cQRzwe=c89eqt&4eRy*9LF_g`^i z557Eb8NJ{5Gp)y~&S5P$uJX^f*Z)TD{^@a}SUs0*Ib%zlX~a;61jmX-jCq&HH$V!D zc>I}ge#iD44{b{hjbqYL|F;|ElJ?iw+Z$PhdT^t9i1~h%68v9DcecMKZC78~h-I5{ z0!U|Gcfx~zU}l1Ya{brX7)W|xK+ zByS+p8jqkib)*CN%E(n(ddt5~T6!1H+r{%v_)n7t(702r z!E$k}+_Gy|`yE}=U^Nm{^Vs>5j6I2!jVG8Qx8DJ!r3En$zT*Y_D`_$)?tB!kk?did zkDH{E;YAMjaqMKE3X(uZES5KbA2YJ+r9-k$?AF8D69S81%@o_!B1bi`$PY$+_+gV& zf%X5LCwK0|S}F9vaNj-#JVIU{r}Km)Me@wfkXTyV&GwzvArfm@YJYht*1~B&H`aB1 zv@03bv(CjGv7#lVtD0SomUv!%M1ANk_2K>BNV`MExzJkADey9*2%afu+NH%Dd8z*s zDV?A}3k+LTc^T$CR(}_EWkiMyeOTbZ3w8&zE!nSWeM-j!L{^5DkuTI1bu@b;Umt=H z$|ratln>FpsAkBhtw?HXN_>5&GVC`jS9P;%u?!er6}Ao$g%-T#Vu z>{IN8ozEYHMe9fPCN}nWShO^wj~w4&aPlt-nNnbIQa=?2r|#v@8jCjr1`Y|vtT1a1 z&-skaSFie1JqG)kX01^_fd%JxHdejqM_9My_znYFyNwl&n8?z?4QMDw-6&s(^FuSq zu7#a?!kjE@HeQ3U*kQ!dj5jz5l4{tOX*Qhcw+x#z>f-HVUcUWqwZuRMJoVEQ&x5x- zcI%tJKT`6x`U?zrrRSzio71e%DfzW&;?L{Gt3S=S{pUxoyjdoD-a)4$aIl0A@0WZq zbMUP#c`)fEskhC|aKhR`bPnQ`A)>}=Rvil?(;oIHY9^n)aJhlG&qs7o;LT|8Wl5R0 z+`i-Sle$-G-@^W~Yd&+`e9PDiTQ=T3{F@tI#Tt|P)kh#skAicRGz+i_{HrAOjvh_# z&n`SzzQdwo(}Qc)Z2$J9zpvZ<^DA>!&G-rp<92);ZIm=VYleMmsd6XQrXT@9E6n+6 z1f=z0n+K7oY*ORSabMzO$glZ;z_M0c^R?Cnr$bL?LQDeni>K)e+EdwPSi)t4?)Gy^i;$e z49?bR0h*?E>f5O!+2oEH`ZhuI~!wS!w=(L$(9*K7OxMa9&OP8^~vU}9gqKs># zzH%Ss811=2z!CiOS?s-A)z{S5ZdHy22C zR`nPDm|DRO3f>?*`be9hD*zAbwTggx1I40ZuZBQNn_H)afJ*}RKJw*4FQjOs$VGo) zIlJbTFK@lPGe2W*sJ}=T;#?-w0Wu8!PwWkL*OC2t$Cby=#Vyu?=REjaxJOBR{}H|8 z*r)m}SJLzF{LrOvdchm}kEp*G(vF`io`>g$Po%9x;%f7e{pv4Q>bHRQJX5z-zE7$V z_!9;m3KYYCq0Nu4wYEw%t>e{HYNIIKR=zEiPS6JFq9_@U4NJ!}`CIaR%F0f7wCg1t z9={g=0gu1Mw}sLXJW|BM;fZvReQXi-PD~Q?5n3hml67}UlXk1mvhM+B3ghy5N(}hS z0_tZd+%9Lvuoy|sZvD zQJ#oZugJhx_k#_<-+EXAUy)<2dgBke8&F2@cd!g=W_hYx28%*?z`mttMcY}?b*#Ak z8R_xdXOp!r0<{cM~ZE5~Bp09+#CBA8gY4+b*Cf_R(t zynbkz+Nd^`4Q2NpyNto_MviUH^#x9Fy)QStK|RPS0OJnC4|U3ozyr}0bToN~-)>w<9#P@P$)7%9_G&dv3F?{SPKXJ+Tb20{3;P1TzK0RBdj?2=M}pgSbxAF zhvYz(mQ~FVxt1h1c8g-;Ip)v6tcaeQVxW zvw!vKmL*GCRei?b#;^L*i9D{)YVR@tD90=SHN$1Q$2WL%j%0K zw5)k^%_A4DZn=k5hhggXJEt}yUD-3C}xs0%M?do-bs-z6<& zi`e(-vmgcfQxE=@^f35R^hdH!N)HFVZRH!3$iNHyUM)=`(%cbDgHaehvx$5|s}k87 zXyR1_gC4i{d_$VV=a1J($f#av=fjOt(B z*KWW=3}*76L}Loy4)RsE$CLr?OQ*s$tUvK<#>Ihv zTH67a&t-XBnG3ia=LUW!&z28?FENv~3tf!iTrj6+7MsAXhPk#?UGN2;!rIiy@*)4H zPf2M{J%zy+{VE&%YzXAO8NDKgB5RTM1{E${LZ}h9&jXL<1m-o!uc&AF4@)klsPA|W z9`ve%FS$fr(5u(MLzi5_A5|Af9`!tytbVS3!K)vCJn%fOzYww46zt2*#=cxC!wBrG zLSw{MJk0EHYDi}Z(iig%9{dy@D}M`IO|a+ACD?2SuO_IilBcx`+#b4O_8?+VrvauL z-Z}-a!VJCV>873auai8zaQ>K@cRt$RiHH{CyUKkM2N?a+<`o^fg-t6?M9ctjUl z#8$B@*fw@6yN^B2USjXCf3TlfJI9!5_Y`BBX1XV>%vS2QX=hKB;-}r|=)uyeS!opl zc7$E~!mbTr*WqdYSJ#>UpW%DM;D^`ce{~%W|9?f3{{)VqIEe*Yk6N(gOl_%%ryfe3 z4nZ%3b&B+Gaz->-d5(4KXEiF{hh zJFK%Umf2SS3mO=t341uc%dZJR*j=DeX}BMP9V$K?i(tMWqQMfV6#REBFI2*5p>z~P z`IcBKEtX0vUNd8oEq$~M6Sc3vIE#hdYq7{_6I6J0vwairosz=#rKpnySu{uu0!J;& zfBq?Q1(DaP@W-FSL^c07P59IL{|YM&{|T0*7E7OKOR^Oce`*!2qCx7MLC)GWIa^|v za3s1r6XF&dKfHQ&pXBl%hWR>=#4Ovdp16cXA3WGgEoXX2T6UHH@9=T{9HACc5OGt; z+raaW)7UZ?{z;efp)}?xjEs?dR^YS2?0xqB;5?o;l#crwim?J43`(W9^fznzAssL! z!McbuT7OjSt^BPP{rcmI;oM_TO(C)MCrjm5f@#Gb7dO&U5Jxg9(ezg@ztDcK^tnGJ z^nR7{wz9`|W1V&rU|@{t27@dHw9|kBXmmis2>jEpc&V}B0ObY0sWHE*I|WR>ZkN>D z1t+5}k}Pp{6YRhUAB16x+dR)BI_Vv1i)xiVS1qblZfdV0kn9Nir$2>%thTT_*d6T| z{D5j@NBl1v&h_J&YUQ5`y;H*#XaBu|JwGxE&tNZ~UDw=PH!1Lf;oQJoXV>ETZ1xRsLG&f{7WoxJ3C7U`@=}d~HjFdVY%aHK zRrK0n#~j$Xfl{Uom;gm+$gPXEw=QDE>g$VIw=ZhlcXSk9tly|nzy3Okt>Dk>9bjWe z)kxcby@7tXR&&_jYy+em;8bLhUbPhU^OstR2)QCnKi4gmUr}m?*yOhl%@(Uc~M{1|M-5bPF?c_xzb?s$gfcIwfgV8Tx2>vE|jM` zZ(?sukT>BZi6*eI?yUKGkTsjx<L@V0KlHmiT?0B>EB_sq|+pAh38m8T$FHnDMe^9Px z&emgFAO?Q$$4OuL&j*}N-onfixB;_FVgpFNvO;(p;G7bVv_bt8f6s)(6INaOTE;8OPOMel4a1A}UI3aMZAVg+8N8AWo6I3T0H=yS#BNdtF^3j`*r5*A z-wau*U$6eq(srUwc^tgqIDR43vm4zIX;aLm5LOp|3Cw2aiTSFJ{l1+YQ+);7fBS8F z7}@meiC{sZb@FSFW>CvDSt_czq?;7oc?Y}Ep8_70>)RhxmmAJ)zf;=eKOe{BoIewpMu zS_3b#H<0`h_Ycv1{!y3veUYB-8;tMZ{=pC&>AMgd8ZE-$kX+Q#3%MAAufG|4NKs;F zTse92e`nS(hqSNIZ7o zQ-qNwll<;+;J8Fz*!qIKi5Pd31P1#I{Ykq5E0*PE7Y~ha)%9kx>j$T2J@)GdZr7k8 zL+hTC*S#MRQ5U#n+lstmw|N-C2J}!za8pEzV)jI}?x{+MHUw_sFY3)nefRWA;7bF2 z6(#w+z}IYll*=r8B01rv?UkXk>vQ3GAgnufv3|pGj4%)oXvO$4$r}ptO(2fpn|rfZ zj5d(_NCIk;d$yE)x_p);HrDMnowr;~TQ=L`7T0X{rn<7Igv7GxsLA4qR+}_npxPqU z)NR^4ur$i$Zdr&5oKxafjvTmCebeUH6Jt^LK6K!~U98CF#1Gc^V8-@EuS+h}&Bs~h zHQNJg)Q_&&j(Z&Y2|TgD95xcj#HEmlWU$wEprBKOiX96DG`3^B4~1+PG6f%I;}&&Bhr%h(@49=iqhE@C01wEpeo&4^e?y*( zo_bR7>{IF(*cg^u^^!sS9*BKT8|k?On`Ef}$xDO%QqO+}rRn|+==WvFmt}_i8L4|} z_cb|z{6RTErG&wu`$A3-^k8}4$cVZCd8`+*ee~B$%PqPItsrl@~d(}+#(Yq8uFsfhvuAr|4xX}j^M;KL zqsq=Lt(;RlqM|I*71J?S_*dV)6@4$5+|nBGpgsM zxnkJG*FT|i;_|U(p#;P>YB2(Gy*=aL|Oj(2`VGT{eHld1s*oqgA`@=e3^oLJ%(1-MF zF4}4XG{0P|ycOeIv`U<~IRNeT$Gl_cs4$Go&dh3BqOf7>PNtKVD?Me{$x|jRJOekq z6|6gZS$&uF)ZT$Do!3(G>A5RZ9rd3}H!gjmmDO&8OnvUQH^rzY4eRRGqMkD-z9kmgQ{4dFSoQ?vfAxn%7l)`Isk}Es@ zwA*f5ndXt^^?6}Z&osEnQ*X!gl7iY^cFX<6dlM7)7T<4;=~Y`$GQBjvu2&4*WQmFQ z74OB}y8P0Vq~ctY;jX(3rrhGBOHvZ?%XrsaM*K>A;_kbxJooOqZ56NR9Z3~-`^>R3 z>qa!zvYBJgao8)89Qs$pgBZumu`_sWv3_UqViFD?gOjFo-&rdO#a-ES% z@P>L-@Wz8vr{tHGTsviIUMX#5fKEG5Hwm$bZ$U2&Mvspv?ZbA;c07M+Ma1{CAo?$L!K8si{z-0*ntVf`l`fhd43X54)^!YJ}t|5D@Cx4PgOhw@5& z>O->Bi|@7BtAKKqoxi0%YwV{nYRtBQ?B&3T1+{{B zphnxc1s#MPBQ;%fVZtR2xI7xfrOYaERuW^6u{rr~t6Efl+Z~U!5h`{b!?| zj5V3x0)FIM4^AeDWh;~(6}Xr-5lrAh&!~PSP5_nC2`K;V`L?UxYbxI`VG=@ecjnmZ zpqtnNe*Plp4{ein(cm~1n&f99rbnu;JPyqauL2gR%$@Pr{Cc&$x|&JD=07$gn?IXc zy+y4Fe9I%*zO(zw?D4v3>_K4gtvYynZ^A`&0GG7_7m7A2P{EEE8-KA^?F=;0kNcM| zFswcHmmOnf?%jFi=Z5K8{UZZMfe(4tQyofx`D1~jrtMUJoi%Wn!vdzkME?%$6|?aO zz*N6s_Q#ekK=m%VZY*G4{r6*6XfPuJe)*YT9U;y|t=ujTlw8@M7d1wx(RX`iqmILv zR9&sM*Q1WP{8>-$?QB1f4IEX6O{;sH$^Fk(hXB7=_T-jo!bf!gAFYleerjkd4v%9bf0F$ic#cjCdi4o$KoIu0TUZR8e!^!^oyk(6!}xwcyP|nF zR7x@r@u_?osZ+d-XSDZb$B3?5p`TVlKQ-tQ_sM#_NzyZ;_2VD#U!;3T_lT_L1-*r8 z3Z?_jTkqnd?m{$xb)=C7mI@l5{DB>jzvASNtCOHXIppK)$nM>tXFKrh7x4@b=-CcB z=LcnjxLf&t16d0-dc?K`wwjB7eH}m9!N69@7o!qUiD3`c2RNJr`x3wu-d2!(NV>$!w^zP*gT#vsU zq-i%CM7_G;Ad4ZEA;R;S6n##vDrrI6kQz~1GpCMeG8vl{Z z;dvr0V2+{GA(+2t{0F)U3TQ2*$xJlX7{S<`X~XagD<3esq`N`uPk;zKiKg;#;t|06 zLp(KkrSX&eZ}8MwN|VWdjAvN+VR!~*80w?R9_S%p5fX(Ye@GT;I)KJ^WTO=QGngvy z4yh&bdq{|#6W!8+jz|loTZ0%V5iqHHbWKZTYjB0+BQZ-bDPa(%CaZ%u0-{rsU=X!I zBu^=u$|X4xN~xxYBigl2qP+#4LT-NI|3^5YooR!3668?%VTcBK19YM}6v;fT{!YHX z4Q!{;wEYgz@q=_F9u1`@s3Exzmh0IQxH!^c*@7y4f1h*1A-slMUxE9mOyW9Mt>6NsC+RVFA?(~n!5$( zZ-l3Sr;S_0W#|o>Uaoaiwaa$u0~7hFFld1jfb^DAJ^(Cs3LT7A+}j9(2!RjUqN*R@3SMK-Gg+| z+TFo6YIGqy@P?Kz=)!76T7io;8iSjF4W%cFw}GSN)hFHsQz`FL37z`5Xw?v1sFl#7 zL>Uql=3+q`G-{9!1Rn--Xw-pB(&$56pz&i+<;I*`@EP(bpnh<6t5HdmhgQ=lC3q-E ztP>{)NRX3){2^$jabJ*^LVB(sT#%jQ)lhbWJc2SqRscZIdX&@6&^1=WeQ+Cp^1vEamB8URtI=p&tFIzbooXX1IGVV2@ka6Qh8)T3hu zWgGY&^+JmweUS5^=%Eu5@1uYY<`*~y<%OUnKs zsQpClU|u0}G%W)h$eO_@X!Q^ehQ;7!EsqAcR$j`Bz@0Y~yvq`C!r2f-WO>2vw9Yp8^UF@;3`FZ2i%h{5< z#-ByGR#x}jy>`i6BAX^hME^lqpapiOkXS&xF9%yPZhRY+cLasV#qF=(wPdZ3mzvH@ zxQTdUl%C>@eWk8L32o!Y!Aau?3ZN`2Rtnsc^c?tw@>2h%ZEV<~MyGipP2l6eClBz80+&3%(|N`NflEQuY3(;EaY|hKjqkck+SCniD{p@f96<0#?n@Q&;fW!HhySqE!bH zOp@u4i70w+dn105?trwN_EnSzU7jW!nBVh(-EFAB0;#-^&Ow}H6Xj_cgnfI(&4J%Ko-s?8XOhML&yHuDVvBd?lO63pbUc&dx;#_jh%tiY z$;n-w>64Ft(eX@4@AAx$e(aNuXZq|e&y3l>zaM%wF#K7IstbE2-5K^wdaUa+WB9X# zF3v~dDEnivC+QsB0_;j!1y3pXTG9Fw)jS%{J#D(%;H9iOXD2u4Cg51G3agH|j;*%BxF$SFacI>1V`}8LKV;vZj;VatO)aP!x ziQXO8I${`Xjuvl1|M&MpY@`F<17PN#cv9s0tTqAy&p zO))gN!DofZ8|sfj-h}!NcR=RdqV*k34pRT6dzu`id%-@IMfa>(##_n5&3K!JN5`{{ zyWQ?`Un{y&{J z51$%9=`(+7*EevEKP}D)@Hh?0+7j$Su0mwN8c48uME7b!)cf&}W78nXaLx_(C3k!O zukTUBqa|}XULVivczxP&lj<6JeLTP8G5FLU1 z`2GlwOe)%~6%U7dD7xb9gRmS;-aZ0LCY81-4s(?JfM5!0k5!+qZ7s>`x^$!gz>cMnns)PwbGr#a;NP5x#lN zx(V+)CIWw!r+XCbjh36kgBdqYN$(N(RB^+D6}qcAg!)GQIxt5Aiu?%3Jp9j z3T;Rm`ba}v!x!3<`ma$q70T8(B#jJ}I`r#?hM}KjB-j5~mo_p{D>S3-BaL5~?jzkg z=~s#N`RRP||>!f)9*JwK)_6)L=cA}6r%!cvuz{{;t{Be9Y2h&0(>yF5;AmkR{ zP)cpb(Gfma$mEV^fWrWTb|}f?{3+T7H#U_`S8r&gw2alBykFX+$#!ZDR?7zqwg;TB zXW{rf63iVg+`Hk!JkmD*0#+(rEigJ2C%Z>d;7}t?c_PsC1pkMYHXN^x{>0IfO-xVj zG9kReo?&&`=P^n5OAFM&ft{2nLz?eT6~ykOHDF-pTpUM07^u(lU)5N-@`*f4fL?Twaa#b108xLS(W(h{xLq3v%*F7OcTs6(wna5|r% zUWg_n@G1Ad41B`CbdKqOfsKIhM91DARO{3_WeTSyM3A}G|2Le-hGefv+3in?q@YcR zp8*Fc5kO{Y6!53<8P#Kk)3nGJ`yVBRrNWI_=KDC>EA?Sjq*tm39TF`zk zB~k}V=c$8(NxR~Ll%Ownz}(ukZ)x;ZYzni%rC(sc9bcg3ManL;4dK!OqYG`B1_Lg+ z8ZzN9I>rL*g5`pD12Zf6wXK^?}5$%$|UN2VcEv z>xJV}O$M;mDhgYJPi%=*qm+yNZ}?x5ddZpXAGN!)}&xmRhm)ieB{M$ATM==oYvjstB#oeSvcq%4>IYemmb(%#dw(JW#y%K zM!*$w$?4`bU)ABQVR{QcQbNP=wGjhB$ic0c)(>iVj>^(E`(`MvW=J_7& zy`*FRyjR^_ycqKgR^+x06efXS*!k9+7 z)&HT{-pybgz#KGc&eeqeg~ zK=o^UvLDaLVI-GBICrCNH@byWMjMB;dReDiw2k_D8}9;CK1=M(Kf0_d zo{;9)p*(1#`nB5D6>M1F7jT0+sLO3#2@ve|?GJZ{tA0eM1Hh8ro)3<=Tz& zV^s5AA|B~}Vd)SxN630sv2_Ot^Br5|6(p?pw9vX4&Rm6EP+I|Gu=vx78|XoL(k)rv zdsbYu=iU_;?N;x_^7M(7_uRW;`R;rC7wCH*Cv}3>&@{V-7j{sOHl!)5{#awt%l;J8f$kLm#1PY_;-Rl^$QE9TJ#&@4xMh_B+?ub1A^co^9n zY8#DwY;yY#xW-QWK`=83`g4b9ClmDqG?JT|9&f-SOqH*lySf<1~3XmVIc%5 z-hm#W;wU=DvQXPVAL{6zL`b3?=7sD$mhL5PI7^c3_IcZ~aDuxZK@C_e^ppK#GTNu5B&Yp?fpw<3UCwkzA@VbdP zA)+PR&-Qhn5(-&%jr^6oRmdXfh(XyS^ntDdeXj20%GIk@!^ViumFgPSXD5v9*nIsg z%!XUl8ogzc)?Z+lf z{K$nP+eW!R6hh$FNfX009qD*f`N|`$KdpoeMcAA2sK6&(%8Wm?OvK>{#sktDM9~Pr z6Oz-xNz0sxleAbsAGvsP;0yPM6DNfi>WwPb0sx7U%cIzR|E^3e(hmi~q#=#8Ur)C( z_Z^)$iKnKzWao1 z{m32oe9}bzq3h#rBkGhjlVaULYr+=FnzBa_}7~*Z*Ft z9K8zP)8**)UkFDQmR8u-rpVDz!G~OTpKiSDkzUi_P;U~pH4on$K$Oj|?l#1GEdth&(CX5#ySo@WyZh^g0MQb+&5-W3 zDQ>3$22n#gPKHy8Qy95k1P`lHJb32u;;=F8+fag2;|%y+68aJl`0(Dc+*@IfDixP*c$~nNVB3y1)B;6#YXd-^}9Zi zd&=X~JE~3k2#;-WMg%M9p~ek{>C_RUD8|7#N$m3;IkG7u-`+El&Ak4maXPF&jXQZl zUZUIseawax3J>BOwCFC=-LLzY8JU&EvQ*ZLY2YSTf7T;3v zo3^}b8aTSQOFM6jBFjRi>JeQ9q=!*KZ-9)2%V=r_9eoB+Ff4%hS;ZFY9xo|&f;#j( z9VBwQ($o54b9s7N8QO-XoM0oJVt+)Wa)D>i0R4)FWGx`ekv+o5A_ZD}KLk&#@IV zuIO9P|DuT#HVnw~UFD45a%mB7YH-9Z7`s{hQk|pzi99#pHCZL>qH^7%g%j(J3*L ziODX`O>%s!Vw9LmraO|8Nk%y?UN-f$%gl%*b}ktemrFKq$u2RY5qBhRkXa(zj>DS`!B@y8YI#zrOYMMfLF(*IC~VQZG&^jfyHwk*p@kVV6wN zJh|9n!M6QqqilD`Mk^~!DUFV%1O~}zmqmi;Xi8v`?M_*5WxZ@kW^yP;q>R8CNJ&Y>Kq^Thq#Uxr3h@P5 zkfbY=A5vN|E_g61)LEZ;LIR{U~B6IgI866SJEyaz!Zi;Pp99 zaUCCFH!q?jhKP7Gl5l6FqFp;on}W&Bb~DQgC1(!vRh{>*4uh_8S7%YLhQawjOC;bw z8+M<)IQWvXJo^|WEw^_~OAqrzZaVwynYPHNivF1s&dsPE$fDh*NZB2&c+8U9qCf01 zMJldneVR#jS@d7KO%aOAqG-Qm43E+N~3-IKsPiak@YSF&A~UWQ}i@4QUCUA^;CzLQ<6&TUucojAe%0)4Mi z=Rlrb$O8}F&Rjkz6Ng)SBABOJ{=(_Z#A426iRzuRrmMH(z#5!_90X@kUwQfv>-Q2J zCPnzbi(EG0{8MNmh@Id-=y;z!(?=tSkCjWW_u{6&MTqf{rTRV#d}8mU#k_~NxanUPUy?miokOWJ{CH8tMUQG1E+Y?T>-*(5ksY|beZ&C@A$x1>`+s> zI{bar8ePO*3Pje{C?7PXB?Mkj6aK1Jr_JLoOMXHL`}+xhU9B>{lKQ^{zd3_^hkP;S zc5!rKD|6`5({yE}F&QPra*X1@9Hy)^pQS?X3hP2yX&(k@Dc`Q%|I?4^{X3Zb%Bz^; zy7s5BOn5KL-*8OzAKSqHGOBmwXm8!1IxnyN3FoK||LI!h_{(3^AGf}zzQgj~yZpDy zF8l5B-c3!tv+6Q3>Ie@D==PkF1kXzsq>v7g^Fyiy4w(;KW@QRh0y2i^38ks5G$U0O zr~4w_qX)#*V59je+$0HkH>et#nIThu&r%jYvUl}jI}p@ z`ss~pr%S^cziey!ve6QC(M=zamGXn@1wCUDb8M=hYGDK#f z4MC?6Y7(j`lqBd*Of6QiT+u9$-A z)SNv*caqK5ot!YbPwf>`r){XS*_-8owNt0o)=i=4{8JF5e~Q}UTO2|@=-az5jkb;c z<(_+f8Qmn!*?jl+-`{=ZY*WJ+x--UUT|<1q5&MbB*DEi>)|7x+gf#&zAz6t@te~{T(~Z+j*PW+Zu3M|S zT6ZHx$A^J&i44_MkMYk}?)6|i#1QEP4^n(HD8WwHNbsu~0cWHzYh9=(QM-GCy^5}F zVb|P+g)8s@c--E3=|WKFXoiqRh`b~xGo0i~*X0@IXcH}cX6I!&>%$P3NlRo8yXG?$ z)_dJ%N7Z}z&gve42YU8#7Q9#G*u0KCUcYLo|KepU8(LP3ZC<{-xp_GoQdfkd8t@)v zi;RqkiHx*`zR!)4%;s2wQ8t^uFh~(*x6y#hSoL_6+2D$dh?Hd)t8z!+DLIsF zmdufnF3j&nM&J{--I5%ko;1Xo&9YG+htHRdZgYfW5O?H*(W};7ahY+EtKW3JetJLG zBI9LOth-2kvd=};1;Y=k^Vv0rhZj^|)JN^N{+VaiU;gZ~>xRvnH*EOaxsSvoCdSwk z69eBl5)vG^VBe=?MMUZ?w#>)~b%-@H%BX!NPJ(OiWv3T1<>hulLwv zlt^2QJ!kk@_C{-FDj_$pw|bkxN_il8^k$KH)M&YLZ<+4JP&jpLRrZyvj1`TD7KbyMr6 z$JuP5|EtZi!H8C;mVOl125NhwAy)lC2Iml;L`Aq*g^cr5s|E) zgs%u$eEu`YgRx-0*Miq^27{bGc*$b_?!`+6@6YU;S$424!vK|_JSsktm0xzLA*1$C z8SY2tm3cgSin5hecb<$-I(g?xeRk1(si|c>rTEgtrP-wiXz)6Ki^Zi?Ph5K0u2$q@$s2zy7*%6M`T!|4d4b#v|c?sGQ&ztkzuha$6`Es#cH>uDf*au zVKCL(GVoz75PSyi0=I35u_<~_j4ej5q^VDXNv#ku&g!izGdXXXvU%!j=W{Jajm7HIm+!BpOG>@dCThYvmJ~% zW{+RJC3${I#(0mA>kD+UJXJQr7DS#K9$0@oUK?437fav4DCU;yr54$s_zkiw9Us&g zH+kC0fIJ^(<4``>Rl;)`z{{Arr0dgR^eBVgUjl~lmCuryqO_k>hD-C$E=&5lryS8_ z8g!Mlbxw(ro>zBnEsol0hs{Q|4fU^)RxXh9v(-cY$n`uTmrhtba^)qXX&jPZmr&#e z=|fR&eAjX@=Yczx(*PI7bgzkRke);ZYUCkONuUKM8%FlQp_-Asae9>ctJIrCsz;>{ zWPcgVC$H4{pOk8vakgeeZ}nd|eXlo*P=Bw2XoZCvI@}@MIN7Mw>fogeN6m6p49iVN zK}=W1vLHYsSr6GDw@{dx3F@<4eOj8pYSkx{n!pbx)^2SHz&}_T$K8SNCt!n*(*Ws^ zc+xLFtdxoIE*_q=Js~0b=xCcy3C*l9Dat(M!hPmDVUOJZC&Lp<;m&??4$e4n^p~^Q za{N-V@73-tmz@3OoY$GXzmnaL<2qZNlp`}%dLWruqvE_NvqvcIIcE=b_KU}mBpZ4f zvZCcJy)`q{`htP(Xr8_Ht`FtHs||6?d;BUTj%VF;wH}{q=-T_S_#Aqb9M7|E!+n-L zPadwmU1m~DNtQl{QI(UWj_GS*y=_)mHuTMiW4C8z$i`H!Eh~bxth-`3wD{q$!Cj)P z!IcFu%L+i#I^9C-rdSJp(Yrn6KAg&;M=WAbIUR!t*7TO9d-Vn~;XrWF1@S9slW>A{ z=nW2+n=E)3eI*x6_8u3!Xy_yt7^)lw58BCBmVt>O%!=+TTWN{Mg+rD!P(5(8E0yCD zfsWJrP@L7Wl4K}7ky5UaJN-Y{(GU1bW_^i1r#j8W-Pw#~ z!1+hRVQx8TlmbdrPovB$vSmX)ztY!GG}0-npT**kr^jcmWP>Z3tY;-8_gpqOll7`C zk4nm!GpMm2|E+ZO$T`#RSbuhI{mez}wJwKc^N^8llgVu9;Gf0M6U5m2278R^@GEep*8ATDDq`JXt9F9xMb5001&skg3syH<=pA z@QAStR~Q;Gl9ADZ2C^7Kdbt$(iPi@PXwwWgA9;I4O=42bfSR6za?N$ykIkBx5MQp3 zno;F4#`P?WOE|0Y#+3PkFHgR)sxcw1ut&VfSv4a{Uml+@VK!fRVpPl6(wOGv327H>-B~-Zz=4v#TbdPyaQd-kRg>qMRyt;?qXjI#%Tu_zL*Tm zh;i*M%aYnhTPoICp3iYwGI-SDp>|7TewFDZMVekR({NJlnO5S}o5$3ev;T3OoI0qX zz*kk(^PGrBW97y2q=C+)4A&>U&6^DkwOOohp99UMBM(M#<|!~r>Gsqi=DzGwtGqt7 zv9C3y){`?#{rZAFd`qwmSv2af3^pbm^N1s@(Bn$T0uCDY!KNjjru^Wp$0rgXNG>`O z;uS(Ql4k{udh(t2=;$2joD6%c%WGfH4wMwS?H2f^^1!2>0#}xU&(UM_V@at6EV?o~ zz97;h!7`DQ6IT##?v)c;5Ea2qy>j9UW1ZHd%G^`%vP+nCd1#*D!4#KP(>-oa@G$ls z%v~aGf<4mR==fTK*}V!fb!nERQ zR?II>&dKN1y{oHx_p7e#Q(YCya7;)98{Nb#qerpG(W5F@Nk-r->i-*IyQsq)(xa=z zdYM9-dP{MTI}o;cZKdK1A~!9GdFjguoWZzm@G5;_<^%^m^4G&W3Rh^3O#3d$nNeEF zhYo3I7(AkWa6|o&BsS|D4BYsLnSBnk;G&lI$@4$J77Z;*WmC&tlDDZTz@yl-kt5Xu zroT5e?TP8z)RZ`Zu?h9^ZubYKpC!Yib@c=uXzusGphn zf|{DZdG;Ra=LueTtL~~UPGg1T@%%5;0D&zM%cLg3an_Gg6I~(q#!psURo$nux*xSh zHP6pU4xGd9%P3(Lqee%vQKK!aX*8N<)F^6;lgH5(&uRRG{Z430ANYp8aCBL584kg~ z7g`5xl$EY{Gr==hxWyi9EQ}j)g)p6@=wY^^eeD`j-!Qm-#NdX8Awzj(X@>v%WNCO_ zA6|RTEHuM8vtt-8qUnP_*wj?**wfVXiAjC2sfkUE3b3Xo$?Gm>Q#^%3bL#u#sv8ER z`roBS;C@-%PL04S`Iq#4k35vVbeK~`!nX2){4{nOt;THXD&0-GJ(z_*p?gjD4rW!K z>b}r@tvjsyN%xEHH{A)HiolvSmc%?PljXoXRm95BlhD1%OpVdpP*ProrNCk*ZeTS| zk6_PWHHU$Y|0=+pG^}nxElVq-K|pL3NduqK>LJ#(5HlK!K|UCAuuTP5RXE}pLYF2` zNe~r2q(c(?<0oQ5L$#w7!Bhky#(3j}(1u_UqmI1 zJWw{IvRL+(T~&F>+VZxnw20iw+RA&sX)4v1OUZE=`7`XMv*Hg8SC5n_Zll>8ZH}{? zUplOI%C&Khc(dE?mdkfd9i61AjTRQy!`yRlRRWuQy_`6txP(6}zZWw+woGqvWaddZfLIUHKD0N>5)}Zls~;kqCHdJ?6I6>j?PFao;fB3>Zp z;Z>X?XGdh`DcRZ6W!akV%^TG>HaT`geZ{DZNYAJei+o46lGi(1$&UBxa~wHJj+8Cu z7<1rY2_4FGvRyu?yd&(wLUBUyYKJ?MRN-_ubJB#xrvsyxdg&+Fw1gjBJRx^R;9JuO zeyE>ebfD&vX4gV?+-hnx1)B0rjS1Y(?kTH?-7t^)5)xdE zsjoIB_k;C~e7ud&`3}j?!i61do!w{GOM3Kw>a@6q?bt(Fz1^i~m7&h9Rid0vV!ppkP*3jM9k0If*G3kz zjqP8z?&#C!{Nw6}ne(Z^uuB|ut#7^Co3GEwym!&zVd|aVMO$|%JZczM?_hBW>APmC z*Vp7Ze4b2w|9o3js{EY#&gMPp&#zy|DmP!{X7;z|UQvJK%AGJWE@bh`)<&_|M}zp84O9Ci2svsrylT73SM1zFinmfipN{>fRDJ>qMUQ{<|AIQ{7{_cp-a zpg^o$BtgS&)XfH6U=zYP3F$0lk%)#7P_JMXqc^}j=n}FF(e5=pmn=RIOYr-L4uiw% zUF6RJDTSj6Xjgz&sET5}q8v-s01HbK*7@|<5MapC^N$OCN_@O&QtwEmXh~1EWx)Mq zG3x#Oih0D)F~($m&#((T>F4)nJw^|xZ5}`K(cG%MqQac~{F0CB^C} zHhA4H`ewQlVm&wZm(>YXO59S`w+QDg4X9guX>yt;aoOCns$@&yj)mtN3McF{ELdZh zom6Qrb1i7RJ5dX&n08pm_;Zv8C}dWHtvbak}BK^*@y`}Sm>Uv+6I}766=Ph>=v9r7x zm|v!6`6QP&%kCukUIxoBq%=q`lW&dFTb3cz9J&G0gWly*=S>_|grr`KOVo&z4@&|9 zFidO6Y^S6ESdPI)??us}hZu)&IBb>=q50v_hRHzKhk<@#48jQKF3)tA`{+CPkpj!L z9_hsg%zc2Lg((Hhedtg)B_SUZSh3&(Z5aGh;z)PmKxB+uS(0L{Fr8=aF}8NpH1FUi zBKewrSHpyUOLJm08!@@sp8BylHU(2SxhglO0wZxMkB*&NtDcnk1qF>aA_V?5iaa-O zXe6tzRrhjv)}SdbN11pnlQ&G>%D?|zVdo5}-O3J2a$9ow9SYxFTU)E%#3G-lE}1^6 zc5F}hUtX`*w^g3=3#P-@+LCRFiPjVw+cqaBZrq01>E5x6hgkD^U0B2_GA40%1+U64 z@Z|-D#O2Is%JHVpo)D8~9Wu<)ix<^aRk(TP6kkEU;r-g`^M4yToDFb|#GHcLoz5(8 zrpp;4NsOK4VgrVc{B5E1Mye}jda*er+Uc&1k{0z!wi;ss)|85xRB3!{n$f?aG`2J= zp`@n^E4(&u@uZTQMn;ax9?&-_#^_G>_NvK?iikl-q@@=}u1s$!a@h5jq{2SK`(ng& zXKqU#SDF}MNY2R|IJ~bt%AAy)n6Ny8eRRHYk$v_eS?cX_MyHxfva=?Qim^n;6(;dA zTavYRA4{^Ys%LtsV|-=Gi0ljc+hz`0S7%r}?#cn?Ws_Exy62eFdsbPerc{piuC(>P zpx;VE-MX{Zm1`u}MA4)`jo^Z%T8+`acq?!MVO_hu)AgbXs-AwU2VrU`o{ z>=ic3613s~2Pg$0O+yP#5K;!Ua%eBAVV`fMS{A2F=Js2A?~7eD!Jt%(m0_ z3^4aGn>P#Bk^@VRj-Xn>5mZgc4=XLrn=#|I3FK7lgY7qM5l{bqBw^D7uSp_>Za1N=`{6r$|I96`qrvl?cyE zBqaYN&!6O9;15goN#;v#;0HHD1G}o3ry%E$e!@si0>Wv$iqm*VEk$ zH+RnNE%o;Fkza7<%fjJ8-os^ESigUivnOB94gUHel6Lc5%&E8CZ#__8;Jlo(wbjb` z*!)RlyZ5~Eu${Z|(CK^u@qxgq#0CO2IYWx<`o1XBYZ1V9GqIczht%SP%oOS1AF>7BQs zf02oMeQR%hUT-3!3YSPCFchqPWrZ$XhJ~y$ZcjZ;bY-{g+Jbs;@A>QjmSd3$=Ejh+DLRx z?Ur%(`Itz_jfue{L_u<2JEWg~%lik?biFlWA3oK&P+uh^Z?2iPwsEnwx_JMbj@46& z4ns47xgGa;@QFIHxJU|>o`_bcHU$BII<5kFfaoDeY`}TwMut|BK52wG@zcAPcipsr z*}v)3)? zQInOhk_4m0>Ld|_nFH(zVZD>I|K+cwUAXhFe-Z9n-bq@S!@|b{+Yd4$Z`~}sNhY-m zAKk&U{gq4@Io$&aR#K;P_Qas{diRYmQ z`w3c-n2?N0PN4jdbaLrC(G;mzN$cANbv{4j11?x{Bf%k87U~RwGCemhUV5u=|GOUw z&*+T1moGX(7UU%Pva@}j?AQxgRayA3e&Lp{zlM}C4SqsXnc3!rH{Q|z2T~_I^Yykp zH?Hw!WqIih^v|1>?fF``m2~3D>B7zM_HZWL#hpd2E)8_F)d>xd%f}&~#q@+(3B71D z@HUR~z;@^WLQyQ_A>cs{D~P};*a}gPYIH4Bqe~?~&=3hku`t9yNN=z~;7DAs1H`cn zN`d2G!MF?Iym$@@`{Fw&9w8rw0<(gFU@$K~5E63I(k7Tk4^uW*PQ9V5Y}efKR`u{v zmI*kjZ6B^~EuXuqtZe7C6^-hOHZ$4oaLMO2k~EKXcXO}scd7nJiGgV~@~>$tVuL!_ zFZCsiOJcaCQZ4-4;a2oE3BRx;;Y#M+ydZu+!a||oqO!8xQ!5%&<*nB7>FMM3<13US zD?0a-m2I6-Q75a2A2p1vkkwU8x$Z-)>{Wf~CYkoeGM#X%+q`LHcbd&1yQWb%Ve_ba zhX2&<+}t{Ku15ANTj@Hf_F$=v;spGX-C z3M$q>I57k{BjocT;rfz0v-iY_&%Zoz{P>A4KRDGbsk8j;7eDe7Dfvw~hN6R8w zq9UBOpgBB_NIL3g~`$;+}ixUAXu2$F^?Uw)L?mh;Cp&_?_Z;IB^?< zzdm=0o6x~a$8~T+|NqOj!xfw118klJV=gWX{*AW3atGQD`({j=*G8KE{l+hoKQDZy zF%rddB>WGpr*rZO?5X!SY!u&xe9&*;1IDlf#ma}IL?EUpEnWp`l3#9s=D*rdIr5n^ zj6`xxuY{jDSE%5-dUh5G?ATM;>`i`h_O3d`p~BG47WckL>>VP9!>&f`xAt7B6&lID}oAcA1qTP-?Pp($f82rgmqyEbmr zfzLW7$w?t0U3Bg;SXE0ADf0Vxn}QxF8+0TBg$qu)&BO#BI~{i($;E~$VD zN6k{J9}-7iTz~_3AjnaNE-HyoKL>FeEflr4mrw(`TecSVUZR1MqzP|fUFPWlw3d*R*&QE$u-MQrS z{e3>W)!%%db_ted5MlgwmZ`NfPkHCMe~MXQEG8!gd^ zucmQzQM@Ud2laTER#(K(iqx4liJ5ch)l)m4C9k}KSHAoEy$e7{FFdtv+x7*_vGxhV z7eARinP?`oZ~pa+U%X0YF~8Q%TKB}0v>8u6u@3qh22s_AxkvbH_^{G zBxH;$`3k649!87=5w<1O)A40)o7jgM(i1yYubI>?(``6Q9$LSS*|7f1neoIS{H}+r zpD(=MES0eSiIjE=NGLn8<8MOi+O_M>v1d1|lSNbzLCmp z<4=m~wF1C?Xe1C5L|r>CT2RrBXpFTSOeI<$FD9A=Y4!}&6VAME?&51&BDd8v${&^Dj7dl&)wVCWn9=# z+sY)oo{-9Zjqx%-uL#?rXJ`U=_3>yr>Uu?qE=7~yBc+VHGx6iXT;Wk>oJY; zebrjoA%7Ep@~OIs7su;jFG>4kGJa8?P_fcJ^2S0PaKeW5`$N1p!GmlYI_fVA_Z3w6 zrLky`2@Rrd00jx@hNjX8D{JG+Q0HYxTc`cv@DSKLkTtB}Ea7q~Ixu?v}`oXIo$7ywqp5KQqn zf?#088kbNaGqV=leDm8!ezdTwxT>Ll=ajWwI)mRk|Btuc^2Y_9fI)Z7hRHj3M~9U# zKRN#S-FJU}ypPL`?AtZrn}l|)+U8q%&pls!anC&~eRh?$og_@ywJ!p>9&)z|Yn2y8 z%`Kh#1)PT#8;8Z%9Psc3@c4-!$Tmze2euOjGly7rZ`rb2_;c)l@Tctq{g2{@vl~*E z*VnHM8wc+)hWZ;CmZ$6GW-~j&Y=*3ppODM_h}WXOPH4R#WnOVkPKVvv!qIg-rk_Oz zUlMZ3YtyJAR&yvo2YUz-<%E6qrkWu9X~p>B`P0X*9^A8d{>BuGN8`(wG2>?` zCR@hL#q-T=q%v>Auwlgx$GTy|nK?U8U%2s@Pn5l*2Gnw8&(d$8S;yXx@U( zqZ%!!P(HOzh#QDkw3fpOBLb%hDe{6mo-x|Jy&%2FHz_*}y1to9z4=S}w~UuCzLY8H zb1ioF8ujeCU85bkb>xe)&~cf&xivRT?>MsduEU)jr(Y4C`D@+2r2b~U-8}pbX4e;l z+;J#Y%v|^zl*A{G#_HIr>#r}{T)QVWRT%vkVfXcNH`6|hP53d_&wU6@h@Z}TC?QcE zWe8P3e{i6{5BLJ`bh!#@HI@rse3R@D77u2h+qm(;Y(g_{sa0hw?p;x)RFmROWb)>T zi*9@8o!b^o+`L(-ZJ0B6|Ngmi8njBlj3nfKGlM(AJxy20K@1}pgB2naT?U0&!w`&g z-+>W@<`8K0YfDKjv@ly1pLp)SlX9wmFxpubI)=V$-h7Ol@&)%uR{@abh=_ zx^ovhb$aPkW*rcg+;@9S%Y01u@q|2hDwfDDIegQw-HnHCoi+9Dfip*A7sd7!!bk5A z_Y94=0VKTU9B?OaV$|~p(|z_=LMPL;@chEq{#ItLFoiL4Bm2gZ*iXqbui)$HSm$`= z);_@13_al^sOe1eCj&PORIZ87GTKRK1S3We9FRb1J`*m;r34VjV1XDE3j3Jc3Byej zk94hCvSdwHVCI5ttGmXf`%JRPgc7qq`W$|Lvpl_iJu!M-H-gy!KjE6ZC9p_S#~ zWWE1OF7*DWBn8g5=t6yo?soBXIN2B!@1W<&z-t#@ zX+7`i>dMRO>ca8ou8rb&UVis;h`}KVQ?OQ81RaJ8JBZqp0&h`ImRL~>*kFt%u<$%G zkT7cazWNK-m)8-sO^6ZJF8t-XFI~TM{$-Ew7aI&cLd-!_*ZsxGG_t}Q!uu%ROLPa} z5t7de9|&)dWMX55=Y`J?3ZEgBDS^Kyo%1}roOo^*w-)Pp59sU|#9Aak)d4yLlNO~* zFy2yEChAd1i>QlyhF}sAQ>aIeZXG>Z zrLeh5N?Q+(8I_;t5hfUssM}}6NAEW>AF_?vPZUOqojDUm1>=a*y0WA-wvFzka5 zgx`>$LZ5PA)aZk4HpZEwmar+2s;Wo|Tt0K0D6VjD^r!frS{3fiT9_`w`Yco;Yr3d2+<_EaJ@vQV8~-gAO4UbRP!dP7&TMi8Y- zdw!aTfG>c$-^~EDR4$|Qwd2H_G;kq=2 z#-R(ZJd<8}cfH(_V!?+^KbKsgv7}fn$yUa{$D2p2$!6@bdG1{SYl_*LVv$wVKIOG0 zTkuhg?2GjYxt!rd*jZ>?0XmC)gW?5Fn)LFu2bJ&uj z6Z#oPEo4l5{Epa@%pz+LK|H3gCB+!q&O`&A__<-K*hgfW(-Xg~PPkbZL+<(QJw=(f z23M~poQLd1bhHyMz>9TwnXr%+fna1#H*G4uVo#WmR0W$ZjmG76%2+1$2(ubd!Srf$ zN#~GBnAkxNS;o*O(5vV%hF~tu2aZfbES(!#kuc&=sLv(l1I%RzG=ZfI#l0Xh!=M8r z4uoejG6KUS8O0Z5W}FMd8w{y3KK|msN8PQh-GkchHdsKrKiJPy56)-au8Wn|RWfIW z5!85f4-D*Dy+KG=ziRjHRh!7*#?`w9F5Z-#&GsxDGiG7zneO@XyEDjd8Nmx#>UZCK z#eT^>g;mAygf>tc$ZMjMAqwww=86;kGCEQzouUUsIZ1p|6x?aRCYleqpW6P+M(|M7 zc&8XXJuGz85Ua_sZP(zNz>PP?mXin;Ta*L?Mu9K|Kv)XhA0%z+(_xiDVFJN{ zy08?mR+H54D4<=pGtVR; z{)+YJD}sJ4$C{d_&6zFyJ?6~FTK~8FDa>Mx!5$j+;feNZ9L|~M>2K!+-C>(bc-WPu zvKx|_nkskpvCV8A)_#?-DVg>_7@=UB;uKjUn`M2pT-S!}YHlzMM*Qeuf$t2Uafg~O8c7MHts zmAr<{&VO*~v~zjcEc3>g#?;itF-^(IpGrAehk{E}r*O(p!ap4i>HcJ1Y5wsBcm6SAy&JA)s)-in>9aW)yP91}qt)s3KKbqS5Y&Hqd8 z>oxPB#5r3_FZ8SyL^RRBOIo=weDnf`5XW23)aQm>X?jYpU6tYE3uB zx|sHm&q6P>)Tm?6liQvC_-&2CfKW`HK2}ljMP+52PVIx7R)&7l97wc^MuNyY&|u@g ziNR9_a8g!3)dcv>pp@ zxL3vLeF8O|grh_Bo-zWf=u`kFbA(AC$q4-ZBL!g}v2w;dhI|#NZ5U||A$icR!h@%j zq*qmT?WoDAQ@X6kZj~SM%e4#dvIz;AUMxD_xBn{nme^n=rY^YnTh19=KqOZ!+d~7BTop= zbzsd2O%RRD{txKx8u{jBNgkWtS5t1Wnbih=r58{)0P6O#8n3~Yl(cM%LXw%a{*y|* z%9dC*yn3ZiCDYoHYACy{NwVprD&NZL;bn<7wXX7$^;uLIm9Q3i!8X2yuDGd&cgUFn z>ncBF10-202>a;*OU&t!P(hfvO{bsWJ)6?=*EIX8Pmf?cp%JqWRY(sLrh(yGw!ZUj z)`%+a))vEA#h?55{twyuo_k6|2ksw9`$xEF$P`o8B z-e9yK43oI!-tU72$v>nNCS~_ewepI|kKfakbXM4v%M0pjj#fQ#f^25V8)I)Q$$GO^ z#+Qt~Y4?OgzUhxurefh_WtHMrj|wGGX4drw?wt`7URFQwu;6FPH}xm&nq(FBB$+Gk zdGPuoif6D1pna8qhYTDPkyGXbX$Vb{b0{J9x-i_K5_*ftuY@V&7`a2Zi*JeD%*P&b z$r(+pg7L(D7yAtpB#%?O{A^-i-o2wR>wLAs%9Ip#RH=@Q)6#yj32PEI zbEEiH%%{@0^@haVXsB>>Y3MQXqPuTF6pb@PB@mu~Ak<5k4jBC(A0RdldIBjkdlo4f zvCoxkSk?yAsP$!z7;o4x+{E1dY4Z%>!z$SdgHJuZ<$%OdJyyG*Kz7HYOY)T}Ud^{Y zBn&K^$J|q?zF+yLHGKc4qo?kU@1b<*{lzP`dhPb>j(;>*X>6!Q z9|(LcHgQh_#t;WZ7*pF4Z5gB$#J7qNB_(%u`WePOvVGn?vm7UcCSJ(hcC?0XdAu=Y z(}ea1t4m+}N$hV-*@|j!2jeX6S4UayUt=Kj@CL-UGZW=%=N90H)V)a5}mCqf%1ZU7Ck=)#@)7gI|D zHjRkEC|lGOJSLg>r6Fe_u{ zcT@xp)M}0m?zFbBZ3c>G9O#^syB+jS19>zZoFA(yxWz&_0kH_bk>J(4{MEZgF=PxG zK15Q9%xV(IuO0}qxR4C!o?A)>u1Aiszzik;&K8LH#TirTm`q3>@QtP`Ho^L+icgqcbfBw3P z1&2>I3_H@jVbzOwFO5uEy+>G{yt}1&cWdkJ=9b;b-olE3{+gQpfr>&eIz$#Gc-c<= zxR}2NR&xwLC75ESJk%pIS4$qs@ILF{o=KVvCy3+Hiz5!Fv8&vDR<4xWMRD%71TU9` z`(f>X)qTj|2hu=?Jd9`}ICsI7E7z)LBBNyX+uvElxr$yNZ~bM#d(T=rM)Sud!Mu{H z4O=@Bvs$W#hwX!gJ*hYMn@hPpc=nucI=PwrF|3gi2#>ajiypCQ`e3}JKr))sPfy-t zb}&EA``Mkrwx-y{T^079-;y$BB!BEN?qc-%}%(>=i7&|v2y7%>@P2js;g%% z@Gb1cFYnWDS)j@R5&gvp_jNPX`5be6?OO5qq&gwU?u0#vW@4le(j)%IVrBR+3cUrO z&GwP{G>*M>;B|u&Rb%tXcGV5@;lDY!Th5!-T^;@=MHjpu}6fxTc{^I zeO?sLJB;Tg$Ney^dN>C_ZAN`CMTb*f{FVX?dcU+FDtdzkk>xk2Xa1JX&u7{Bi^xJg zofAIe!~DvX%<`4^Pjplcr|*5ch}k496mH31%T)*;AQK3)QFsXdvWhlKib!|ChH|21 z*{{}+;@CsNO&bUdk_3Lo0{o6$i0X#T6J9)6@=|;PCCLNjzO)5OPBjH?D5>IG;Jefd z6F0yo8SVFneAJT;_cE#bj@0Iu<>ST?S8n~ydl#|xyl`JQ&(1E|eRF+|iy1dgZpp5_ zW%svEF!z$yq`b78GV!uQN9uCi%=qz)JE!i*A@Q=ZoV2{8Rw4`>smpcIQ?A^)BY>$S zA@iHhkmp8=Ej4lqIFZu{zQo8si$!_?qPD2kL-doe=COVpMD%zbBt9(oQTm8R6;M!9 zw;%9Rd|Tj2Ni`qT*a|`RMPq7;X*9EElqn^}B>Xs(8VZ*rljP!XC?za;_N;8~T-n)Y zdnZlm=;(d+tbFcVIrcg_CQa&{I%7swcQ>1voE%CP@4)|LQb`{(dhprNrqomub3^Z> z$sHZ@gpFqvbLJ?{lKy$Pb5ifa=jiUa?(NCKeWW#cJFqzme#*CT&FG&WbTR@BPZPA0 z%Mb&45Lr)7VdT6Bo5Rc(or$5O1;H$X$V*uq9U3~C5v$ntQ2$Tdf1rt$AVt?A*u(&|}GF+C{zRJ}pMyp9w$MEG3EY>*#Nuz#BKtKR0H zt6%nLi}N(HFIeR-TTE#Mebd{HmMXaP|8eLNIrDoaEa1D6GC0o7DHzECndxyNm#`b& z<0jZSqWi`&nSD#a4#0bfo#B>;r^q*~mslFM5-q-6(qUfi7nCQKCMdZ5Tp{d?Nst@p z49(MnE>K4RFZDY?8qcUTES12}0hHe3lnonk zhP<_EVDIEr(3`IFxXLn47&7Xh3ms3Ag(J~aFQ+VDyW;TSJ*h@R&faTIJ7bUbjVQ}B zoJg;8Wn_l;b=~Jq_LFv!W~{Xc+lOy1EGmf3aWp^dSd|hCN*3Epwbx1udVBI@$?0{3 z6bmnAXC=#9lL%UkF<>uh;t>1*yLJib#vEqsQq}ToZdQ$yu6y zr#`J#<8X~79^tNn6c77ZY5%hQ`*)@o^jUkR-Rp?`d_{F>y8h0zT4#EC=(=eqT*+Qi zURCN}pmm3huAtu8Y|zveIdeSnrVpZpc?Gi^jprPF;Xr_2U^CXtlI6{vlPe3S)qY(l zyq1+2V(SpR>p0hF@AL4I#;*%WYL*o|2JooHnD69L!6V9``?v=1h)2WwFh!}20K^${ z7k=+_gKF08TffS5g`+n&)bJ(zPKC zisBV^bHjXDbP?7zsaYdw8lA^;b5qz&WZpd2lWoooK2ADH_-hHN%(a_EoG8Z}*^4}k zZjlO5pGz+~nTs_HP#ufHZ=nXoi2tVNLz9F&N9z8>CF#4DuILRk=0=ByONS3Hb(Q1_ z`#sJ$sn9q;D#F4o(G(vi2dOx8XiuuaNJ)hw_827<#^WNX2<^Y-KA-^eV9h9gY+c=G zg>tl2ot2!LDK`kuf@(x4)o`v(9-n3|Mq@wvZwbh6GRI_OjLAG-r&Uykc=xE9;iH$#ozW+Yy>*3zB>Uqe zWVST_+V7H(Su-gKS?S^8BqY;DNeF022K;u8auXmEIUz5=W)6Ho5)tpeguo9^337(4 zd%pKE;cMY0ue&1av>~%W>r8AX*~0$9G#{5-xnb4KH}6X~8gdWLIO~etv!<>h%XliI z!JU~MJ~ZQj#8f|XJ|v7pl$fiyBvRPxY<=9hE;SgIEVG;Hdu7pu^9y7tnGHl%Dm7`aA8-Pk`RdOzHy=Kr!I1I4A0 z!X9Vqd2}EYq8+H~l|~oLFOZ8JC=s5{$w^_Ck=|>akGDG3gXOgfUzLy&+5t&I5#s!A zKz>vmVn4#jI#UNrGsZ`h-ylVKA*vy4M~Zz>ER8_701K2Tq9G8$Vikol1mn?_KEj_U zw}b#@VyXD$N0#rn>;+wfjRex|(FT60O8BOp-RDp=wRi%1erB4l3o;w~nR;d76y*lP z!C1#yGG-6UaNI!&TWT74f`MW-*=}JD7;J~w)wLY==J)`XaD^3Ly`TJD#=VZn{8^MJdF_s$D5?WMg6$nY~&D}IyDfO zM)6ZRwASy(swxPIR*D%s37L_>`QcOtXXGm}=u~P2BmfsG(ojJiIs`FMgP-a+5Vrw& zG&c&N)yG4cr?MqjV4gM1L)52MSO}g_n<1k}0guH?T=tw|CK(Sk2ru?;XN7b3RepZm zEO&U4DdRP1H&a=v(HVurha~L6T!ST4mr|l2A1s;JU}{QI4!%%UB%5Pl%-2eb=a98C z`ROdT!Ijy@=pCPP!tC5O(|N96`17V8@xs~ri%II5Rmnv8VAp(R)Q=dwjgg%5&eF@@ znxlMjs%CPh^=|h0*@5N78Oc+E`qSxo#z%b*zVR6IKn*`_3!~!enpzX(HA(F6D7<8# zaU5a@XNtC|EMR>VaAs-(7L^15qdw<;gzSs)d+_fr!NCZ2LO3XazyR@&E&>Xo5d8fV ztsu}-ArO$JfI+1JNc!-wHsgFgO0~k&kQ+5aHGyCx|0EmI%0`)OMa&6xJN&c0o~dga zxg>VmOFaxzf*RHGB@BEK%lW@*4eRx5IKEqW|80(Yu*}U9Zl>`0=9`5Jr-l>jieseW zzKYlj!Y^;DB5eO&l6qIUFu05u^6Nd!AqNwF%q=gdyf9UDixK`ZciZ*TpBa9R3B0T` z$zM>L=LBA?({jI&@)c)hb1!jC-XP?LxSomD%(6nNj*4;v_0|Jl{s(Ac6$!LM4iJRT z!7z-3p(tsP2V(+F2paYW{{h+@+0oNb)xU{!lgI-t!tYk0Zux!nByAm;*I(7pyPaW# z8<{D)=S<_-6*HGjo3>)+a)z5WXZI8a35GSx)(433%Ps=X@7fd=8_W5bDb z)d7-uqC)sej8kYu&4zV+5PBD?%FhKlVAf#Rk%7qwH$`cP^&%jVrZS)gNLaS%T!O8i zZjc?D$$azYN)7k9l5A4;ElK4*)2tUdl?~*fYp%Wa>7GJYs^7xYZ@O+{5VUUU7Y8N#6}cgJK`5J&nQyy=9-s1Np>AHg2;ag zLFo@c{Qom#ku~O@kq6fGJ?JJhUWWXYIe7)1SB`z}Jbm_i#_9^e5qWnh{7Uw7<1XXy zvV`3Ud!e`c!BO}jXd_DdduR6l)u>&f1kC&23&w1X)&|;ZqOEi6H$#}T zD?|2Aw@BvqoE8$U9Q>Yvx-zMl$}1OM-Wq)8%2Wcc0_TK%YB992Voha&4E{O>1}8>m z2vAQ=7@IEnN^zH*qBOAYgqT@-i0<$Kxa7Vme0Jav)b%%P`iw|F+qCtwwQIiE!aU^2 zwA(Tr&J3G9gIl~;_(XV3_~PI}q<2dthP|<;H-5GepABEGU;pJzxtVr*W^R_v2GjyS z%LMa^Ub`mRzD$xI`A?b{`%_M)!;#^jP3Bhoo6Wt;mNnFLw43=B zEFIr%^Cka6(fjou+C|RTGMtV~o1Mbzdw@0L@_PUwjM+DT1AOKHK6I`19q3&3rT|88 z$jR0x`RA{VEkFYR07qs{1~=y)0Pw9Qthh2<1QNRxQ5Of$DpWT!dq;5@7k_bJHyuaj zTj!+lvq5?VxnF2vR?_bSyLaPCCgA{VH6`4`(0fq0MYt$}Z$eUt^?ia-slmjvMV zPl8*>+SgD0boZ;e)-v*&vKQ`q{*m{E>DM~hnK*cE3ZICzX@c>)&pca2KC1fdqi_BE??Tm&#&DlyW?KE5mKVq74tuj&fC~h@ zKa92QaV}Yu<-%0w9JNM~O=;-A#Tb@i`H=;G^>CC4e!OwVM(^~b4LjC<^znwB8HO?(%*xIjcwF*tm>M86uo?;LEl;CsmJ$UmI(p;-i7Z7!KK3|*c zkuZ(3Q>02)ckhg7bVhGCvK6Jwj-8b|lWSQfzgzgSK&`1wc4OYJgMO!#>%o>B8U&Pk zK%}wMLeo!$2)Bd+uy*qr0Yg z3CT(zRa7vama5u~UqN99T(s>IKdovNI!A~GDP4H^0o#B7=Q zk1+o%@B*f_nBd2BRVFc{j}a4zu>lxTutT$h@o)-;X+3O2QdOE$wgkRbxqRGNMsjl{vZ65>*VDoW5{BrGGwBQ`e8M~;VJ?zG0*6SvE^{#j;`K zTyS1jR&^*Zvwd1yR)Ie+;1eD|DKKH3jw~^5+rxA9iFQL+U744)WSg$cQ|9lLk_;s! zoi-a~I7&dmh`LO$IOL$uz&I5FTPj|x@Uo}^26L* z{P$71_w5xTox(uVuz?u;EaGL6r^;_6uWehJ54QQS)G5Ja zAVO2q$v0L@iVCV5o3>uJy}7A6mrEJnoSxo1zBM&fm^nc1@;{HoI#z%O^O=5Yi3BeP zC4k*~=o=~@Eb~Dl=ywG%co1CfiRdII2`c_Xa+#W1zoRHJsXRY7*)=~=-N|vC>csi3 z3PY6f3OCoHTiu>)5hpiHB}?j`6Rt8KOZTk+Vj#=B(dzO zs_d-cRV^%|LyQ#4sTd7<#M641Wfb+w}W}5hP%& zmB{?OJkhBuEY;40={HwDHsWpw_Lk{8hp(xU_Kw+7E??NbEZf>8_oYTPliiWAfhGE~ z-jZd~sx^%(<>gx@bz8HSP0SmfnNwAjlQ}%OnJ{u+kVaGmeR6QPCYc{zE17)jZi_{4 z7?v53#!A|Z_VLU^(m>`gt=47T)yik|$z_<>l!Gg|HQY1Ua$pQI6Gq_3Hpomj!^`0e zD&}2CcrF2zlj+pbQXAKOt(OB=JEMpDF6eko^G~>3G0g1T&02k+y-p zL3}T@&C~bc?Ko4AFYe)t_+M-jy$1?cT+htXxpkL5=PHY4rKG2fYVB8%0bbePI?8O$ zNS#?+&M;Z2sqLZUl;q@aN{ALX2xBuP$eL7qWzmeZOtX2+D8WZuQ}gnsI=4;gbjV$q zy<~p6Q|>sogE+IZ^Ye4ET-zVC%N^u!Qi)P{>?UQ`3;0hoC4YC%h@; zoi3Lvcl?UBF(yl9dRI{;FU?F%%_Nz;G$+^Pa-Yo0mT?Z3yS}={91NwV21Di%%pKZ9 zz0RfAyL9?Q?R{yPqiaUguxw_1Q&W8=%liByYDQ-cc)UrTB#*DeX0@8lRzv}1XJ**r z+xCpi>^JM1(lSTYj0glcPR3k!(@obgIfTj7S%SHvJEykg1}(Y_E@yX3TU*QSTs}i* z3FNg+?HrYd5)YXSDc?|AUthby;q$4XBGDn=e|~-x|Fl+rCdUN=BWgxvr8TZe@}UVy z-jmS+lTD-7!MX^aE1f>*bFQs#XsBO{I2ma|DrD|Ec?Wz*O|ZYFApUDL&Akp6OghB$ zPlB{q5En4cK?x3K5_$v(N4<=2kOg`HL#b~Ot`_suQM`hzCFUB!sSw41c;F0@f8tKc zPbhtXye7UOgrz@qXuKQ-D2aY+`BqMt!@lfrhKx=3q@;e6;15f)jpTNTseomJ#P>}? zYA~42s#4O^eIL|1T+QtabIZQ^aGGxq+3gD?^9_4%B}{v>%g|!g=jNDQiRnaDl%8KU z+TwCG6-U#HRU{+PWy;CbXLKCvn0TyX@*U$R+#%F&Z)w^-vT=J;^A09=*Iso}d*A*^ zcJ=i8hmR-K4Ks&TT{A!0IHjtIG-mIcu5?b?zhtsky_Zyu3XWu$YiBW%Sr%=$s>;l+aKoN z5Vl@C!in}Yg6!-Gi2Zw9d?&>%TuGTt1Zilz5Cqt?XQht|edlG*&XRN@4+g@m{}#E< z;f~3euaca*BIcgDI?@AKB9koSZfCzl#o`qShw#oYrFxWX0weJo*T#!{OeCSywiKsb z*cGWP)(|4uixWqLU{iufTO{63QyqJ$cHfJ*PLbx}KGAm-H;Ggfm%*_xkr=^tK|~8is5YTrXpgwy|7j#r0kCsYczV5My_Hxxm2N6V_Tz@%TaSuYJN?v zGs(0=r<90g)ho4fCCe+M3K>~=9VbE2GnLM&*UFKP-Jo%poDQhUbl5XE85Tu1dA&}p zQD@uqO1;tSFypLVFO`{5HO7wE7`;rz%eBVFVvD=r`mqv@m&#Qtm0Yhvz0ga03Z2SC z-k0K>5|!SRT9rbM3_3jCr&24lC=3TFhmPSS=sc9jwY-qhDFci+m!OPDPH`LnV!#yM zco@(i7#!WdG)AJq<;oCK-+e3uk!c5HEhIYm(}BJ`zVt!yn;{q_kzfR}dEi@b5sgTf z-XFTh?@}QwSRzrYTvs-kO7g0AROvC{l1AycDvc6QYe&WU83EcSJ`Aj z1zyzPH8l*+bK4VjW+l39GTZGXwnV*Iq2y(y3tEWrSm`M5V8)eaf9o~m20TrPAw_jF zx%i21D~REzS;Kn0SqgWOe(m8>=~@smx~(UJgJvXD=(cM@j(%X z0V}QeY>I;!Syt!}UYcUGsQI_2A|0Oiiii#b6@E$xM3Bpmq~e8m`<0ny{LcP&u4aC= zcQ1KCRTDiTd|p)JGil@!nM!Up{7`2?G z^g5+ltx>RNcICS)Mb$Qql2yxeR-3_TG{J3LsyCReW`i3$3PcX#QmszHD|jj6)GK6i ztHn}LjW6e;6vqmISjZY0fab*T#!p@X8l8w`m|L2QHwF8Va`BN@-j zB>KXN%%mi{%c@qZl}@9_?e!$OZB97~6;CVs?8b^IVTqaM2Q^DlCRN<{S=lr%uU1>_ zF0b3~bXnbU++{cV+}_N>3f*HSsSH#Sj6i}7x+A6WrqZFE?>*!5X_2)cPNy{5e{YAV z95b8#HW?WB3lUv=Dk^O@+RG0_G+OkZ$#i23a zLWSO7!ENFWCsQJ%?5X{cO1ChuANoer2b1vZr48l=iA=$BQj1b_Kai%Vsm85~SoMxJM&x zwfMn1Xq_**$KfbPwqCW%Ty?2{6w{z@n6zL=atY5%B=;llya#}rc~>VpuI+mTC0#@&tNcG zb#gs87^!G2^&U>tLSMf{ikSTU;!u6P|S7s0B;uXxK`2H;s z1S`RBvAHYcHICVss+p*pi@PZ&6wBwvXEZ&1g`4_)RuS`~V3F|~;ma_@E=6fdoY-U~ zi(2(EjaJ__x2t`8ZG+$M_l>M+pU^$6Bfe+$G^eJdgvYkboVj4Ztm$Lg(&%1W_soTh zx)XC9YK4hu-qcsZD;;)8a*`!C6Dc?BVV7DJ)h7lFdIr;jk!nnKr`ANWGQh_a7O7d9 zsxn)USBKY|%zC3*BMSxtb@k)MUo&(3=%x`Nac}(inbRlaWX@}y-o0Sa%&FsB)6>#Y zMz_uAS~_oL=lD^nX=&>03Ywq6s!|>}Ndgj0N@{LalBHuztyO2TNW6K8rewJ-DI>+; zl4zBFThMG}fnqw9Jm3vGTr#OTIW;>3`YM66Ucudi`mS1NaMIxsHalS}MvKzb=n!uN zfj|xh#F-!k3#Fw-tgn!*Hx6Rz4IL*)mkH|C1P&EvuTUkrl)8HC!{532yVRHjvTZ#3 zdx=Ktum`k~vksr9+3R%`gi=yNGycFxZP~&n3T42C3@N|JGMcI6CzI=RW@8q3lwO7( zz221CHMzZEBytA_8|u!^m@$d&1OooX+DQ{gy5v{b2j)Zz&G{7yvY5>kRi2bLY6v{GTfwC zRzTncJ{t{MIoT5mHjHdG#GgmB}GrfIG zT1H0dSnMrXioMYpaM!_lq%5HnJg|fMU>cDgJ`d;}V)GCYf~sxw4=@B(PebI1*)RV2 z4d9GYe{_^Hdt`6V>&a^;jhk0Fa?yx|PZtDiwm`wt3r8#(Svhaqq_xSf_wk>9o@QMzvRM+>fmVME1H&e&BY>i+O1E7ID|J2gHaUAJ*h(4+(lvND{yC zapd(p@IXyaF@_F%92J84Am%Hzb2GmuErUx)3oo&_92E{kp9M&*@DPK9zW1@)h5LA3 zJnpjaA>k*`;0yD((M;ES?_qYUl}d<#>wZf<|1G4Bw)ftXNX($UDzjwWZw2jJ8m$K2 zS^mM_LM@AUG$p$edCEp6Je}}n!k^Jf&s&@l zqFR%zDJ@R|yTF2qQ*eYweZ~x%lE@h;DuS?t)x&&I$w`xv31ibTM%Lp(@S4oc8PZKM zzb04?w=X41W!jY5=K0M{ENYe-kRBz}nJV$ybl``qG})_=hEnt@l5RAm%NXm75HC>@ z3DO^{tX`$ss7XeyADM)e(fV$kM4=>vk@7@N7-6Euot>d!iAILlpRHo5lT>oG zlvPON*D&)lQg}yWqC7Nnq&p`OGC!v-G1N9&TR>NA;=tildk`Yl#oEmyWBb*xN*5X#H#nU<7SMi(_Iq*|7G zzox?T({7MS0d3QekTr`{h-&PIVSwN$1zO1a5eUAQ1qs*%gI8aan5z%tC8{oGM@ zka{K~+Xk({z6O+cCuX=s99$mQKrx33w_5l>QU%r!q5^Y=gj(1eG4^>Bt^BBZM$a4L zx1lfr4n~4h*rnQ75%cgo`XAUsk$(tlB;q;v`2wRbm4Vk3k*(OJuf5x-RjQc9-X_1v zd2NBUw!~5S$Ru8oYcf<#$jG+agBd-ZRHs?K5aaY); z@g}*LBO(30qe?Q$m5$O$8G4&$R6$0>Rpa#qrY8jqk$`uBFFkf!iDGeOtIv|8yXYUz zlQoRXVzH=xuV9su)Dff4tE~p#v1;3dO0Q8KTp36iwPVC#veV7Z@|W z7NiCYhv(M1VBV*?$MFdpxs}`<&}BKH+e(3rZZy^(biDznWMLJES&Y9p2uTIOq=^z^ zkVJW60Tf9Bg(Ymf7Gy}Ew2?wvocSVA6h#m!z~GFPUX&YVzkqsyWE*Yi=_Q8qQo8Jm zCHE_r^(*JT&Pev7?D9nonN3a{~|iw6Tk^cMmY!8+u_J$&@L` ztFbZZPL+lnn8gdWVE z;1RQP)c~gx5@>idD5OaW_GB^B{zmx%RO+*`Q7?EzIO?T<@^bhydjk|8u-}O^j*`hC z!zW7P(yJg~GCV8WuMGsW`(-T84E|~O@ZtUa%w%$07#F*}|3mVT!5;e~GtMtK$$POS zxSWUPhnFz86RpN3&+IB9IKBxrtV7@{DASwH?rtmL6(tJ=97Pc75^ru3s5+ zM#I~!`h{tb=9E;Qpj4@`3B3dT8&_vA>BRVXiYpHTSAP2sxPqS3#Tn9PVC?CHMIS;W zoWz9TiGd=d2-l>PU787BASwI+A_$zK;G%dDXH9WhPw^(s8KMMLMx_L}BF92ndLHAM zZZp#Hj5(Gm`9!F1{r|91N^l zOYX+t%Y{sC9FCG~lO-d)*!Z}Vlc^Q4+m*}ul*{hDFl80Rb^#Sj1feAdF#M1&rvrs3_*_F0OG^TxGiE z{i<&FFtED&fA4+o`yNeC-@0|`R6cd;oKvURI1v=pxL$mxI1Z<2dqF~05^;o-_7D?r z#d$bon4iT zTjH@9*6UJq1|`Rrta8+!8X^2Lqfr>K*9w*&X;u$?kbY#VtxNW1=GKISAr&(%WWx`2I*mR+XVM<&D*fUcGJ+Wn){g|c zgn80hsVDb`&@B&6@CSTc~wxl^NCu5{>Zu~%k=uFom371h;@5Vo*PX6$ZI z3pQg)Z0Ye{&ZMP#7iOoyVhnk#RLq5~O&#<<@bjV8GNT!0FC)B5=Fg{_>E`(aKlnoy z%oj${P4ifA9$CO+$^3a7N4?@nX(;@vUV=j`C23#N&*G=9YwHF|>q z-3R|b_utWTfzFjGnjKoZ`SP|+hf`}kQkGV7-1pdIzZy;&ldb9`gELi=({KKLR_Q6d z9=@y$W{36Ydv_f(Ypphm&g9Y??91;zLjRVN;Vf!!C1nut%vaZ@X_KJbGidcG>zD4h zj~)0WielJP+^)=qk3#5iSv}ZHW5k7BmzY?bPz}sAxia`wfgmNS6tB*2S4&c)IxT94 z79`T}`d?SAG^Se8g=BkLda63vmtu1cn)%{DqXm+9!EAE4(%l-3$v*FovqoBN2CFj) z1-T)dJa)}X@931#RBJI&g3MY1hNtPbhqf5u>B}e>y~TEuHYKIy51%h`2!3~RQmW7B z%tRh`i+j)G_kLOGa%87vBs+4P58VCtzvxh9$RO%rS9c?9fRkXK5J0`L14(??xrW3? zWaekgc|Gn06O-r@^jX{!(VJ9vD#&H@2<=Uekjuyu+gadd_Ixv(<@TT_5`fhS2r_{B zx6`Af|8{=KJAubTHT;^Y*!Uw|xtaaK&twf8o@ixf8bs-$n9CSKv-$sJIojNm;PF;bp#%yKs_>r~6)``^fm$ z#HU}2IfO4?Bjb_h3Y--f20s=?@Ji78!NAY#kH85h`*kv3$gB$N-a4^q^=cerd~)^b zHDHYzS3mR&{gtSmA!^CKnm!pjw3@uMnluvins+~yaHD*EhCKauL69{TAgT8XFUH~qw(9};i-^iz5= z_P!7xr46({e>nOX-E)XN9r}#VlLFNLE@=^;Cyf7QAC_Z$ZQ`yuI5~%o&(7ivaK_76 zY4%~a25_c_38gt3jmgE%)w6gQDhv7JntC^u7yHw~;WS@qN#CA>$EA78iu=_L6K4&p z?N?k;F>Y|rz9pqT2H-C)?bEv{0no8S1`s4qT18R+9>c|%Ej{{_m3iI3*{7_CCw`$b9j&bMdcpP_)7rT{-ZB+wi~2x(5_}^*qyNa@PKz?v&8Bbt^Opg z_=MG+AD5D;iy=lA)y2wy69H>E?m;+0W*<31x8u9x$PqHDVC`C>U%Phg$cHwM!oP>< z@rOo!#-F5bFjJnR&+Vh+X zLAOjhL8lmHlG~S&&^Rw7w=IjpCW(>T8pcF%N)_jxiiKWP{;cSjXqLY!W%Jn5(M=He z1e->ej@_K{dlABz--UE-9>Y*TI0qDCHoLk|FgimNX`SCnk4ozms}TruvlWaA+47Zh zEV7LYh62A`g}VuXUQc!|$9WmqgprLkZpnnhZ)~_Q!x(%}%?s#c>>R2q5tAEqp#ydy zl&s!IG)9LDPF(9!QVh`3q@>irt*a|FNiFOH3kYFky3>`K>T-F#eZ5{6dvvE+pu0s< zxKmC2&!i5chVZ0XOPc$Vq|S6>vWffxw5D_ikfx@1eSN&X6b6>+G3$U<1GKzEf!aig zY6B>dD;Xt%>dK@udjOp3O7VI7_@GM$7DqY|BI#WsN|XYLXRXW0D&ut3W(4X|P$Jcm9iOlaA`#Ep86TNNlCcEhvp%s_vUo0~ zk%yg(AJaZgCwMo>DLE6+4LQRg^fX%1bXe7WUZdHQk`u_u4rRGLW+Osso64AOFc$lB zTso~m;|+(Sxq*l$&0;cH(matsE{;5VH3qHD7Y-H}ZK+zlRqZvgl6bdZiU`~EU*rPE>Mqm*p6=!6n!r`ylGccMH3VTuG9n(eK{9zmp#q~Fs#mK97E-X0N<&_OtTa|+lUHL+)*-JFxyWi18JR^qZdPQs zClbubMv)=&U_~wjd{VMS`m(&~Tg@)ZAxe3zov!`MLDCw2ojMi)*=L&ZJvA zq7z|Yo#-Sx9NXa&pGk?1)VuJwNW>l*HsCQWL zkpVT>k$kL9(mO0pM*_9cU^hE$cB7VIf@sTb$>n8W0SLpLPIIC}Mw`W9&om~fKi2DD zegXc^WU<+CN4*h-8yc0y3~NY=It(rnNfK2qx}X4He{6fZhLMrhVpzNknZ8d?vPTUU?5EQXDv={}st!I=$fkvzsqk$Mn(`EHhjtq0fv#oo7<*dv#@Q_sOB8}YaV_1j0IOun?7uKRt|WYM{0mIKYGL2&&ms#>zDySUluB=#FQ7>me2*HehH~3 z4fsPBEWKjtgytbILk$lbG2U@>g=rzf3Q60qon7_eFPSR*t2vWL(FHS6Borr)KJ`^bcw#c(1vZj-+iRl!AE*M@^0f) z`Y1`BPLkN4Wcui|OWIJ>y|(hyO8h4?=yS*DbH|U9s$=BTf3#f<&c1GkZ!b26FUsFd z{7N>OL;i9#c4y^Ih+u^_cS~bx@5a=|mekc`KRvLT?x**!rU%IWRqz@1>X29eHssY# zh0uR!(U8KzAw@!f&iMuZe<3&j^2Z-`{;(7Op~c9=nZNrXuMwap)L>U(fY$>BB*Y1-1u|!Z^G=q(@miV{uUw&z90)j^x+u&@G$-G&>`YK%;pC~`mjg7 zRa(V;h+^*jP|N3WAwTwQ;|NKm!TShAB^UFjhnT0LVn~&l@-9ctO z`sR^GVMZ?~M&i8Q5@{k@ij^5oA<84lP`MKKrgcLr7+PBox3b3PC6X;LmQTQE7qIdPEhS87?X1j;!IWj?7()IRE zjPc9J5nNS2v6`nqaly-<1uuU?w{axzPeGM%fYBdOLtTF{?4GLZTk} zmn3w5E`g!LT_21gkAL_ssT}|Am@)K)4_ay858t6LjDM%KbqR?qCsF$5a{Bg?#q{mv z^i2|7P9oym@$Zctdod`f`d}=1;=}iZ!3_LNcksnaNak{RToiSF20zjYE-$f$w1kyH zOO!&}1agM1C5vh1gz+?!ETK1$Gg2pY-c28)kKax0O3zTB1< z*F|U>LHfPQlD|sZM+~R!uL9AMS4lrErjV^+1S{I=mcQWb!xp#`J0B0!(}uHl>OT2{rQ=yL(g%LftpY=BgJ!=l7=gdSv| z&wtnO-Kv(=V^$7d{eAs6^o0N^2aaL%d8GNa{@azqSB_cDGWZt2tgM9?|949NP~3sQ zf5*(Gmk<$|m-acS9_18MluqAceZxU{2oTyqsXI-euE_D@`vi%(j@TTqY^0Uor09 z)o5om>!8sdHcJabz}n(|Ns`G`WwvA&mZz7uCOd5U1cExX+G$O0#p_Ek%x>06qOSQj zFjS7xI-F|Z-?|x-D(jmgu%T+MubeVnr%bXcE2i{FPgB~m(}EUTb(W_V^Gw~0}C%5SZQD;$?Oy}vN9;C0z@{$6T$!anw3p`oX zNS~I?)6XhU+O#4lN_pou@aOb4*2Kp!dH)-a!`$i1tq*R4^@Ru54E{!+LOb8ROXJ3w z|4(}q$-8%G+^#jz+l-l(`*TS^e?dQ_?;hw^gPy)T(bHo~eXvTv)nDl84-cKC(IS0c zHcsN{D@SVWDJtP8S4tVoX4rctR8)yjt*&iiW&O|yPEZZ4ubecEkAU*YJ$xROm5l&v zRhB1Tg>yq@Wq~)d%E~&>s`B`HOe3a2lHW zj@*_Xi9~jd>BWG9qiXy0O91!oSI?lMwc*C5s@6at#WWVE3nI&xUwg{8Sp=eptHY;$TgfO4{Qrc{U1saHp`tH<=Hb(*5l zq1U?|EX|;i+4c3g!-w@j8i#A`uuPVwc64=i6lpMDB!wUHnTMr6gSXqQctr6cC?6V+ zH5;Z9YY3}s5%F7O?f2U0Qj*2Szih#BX$%|uztcsRW(Z+0KV$)-$a;h2Etd>d(0EEb zGi-^xgc;6!pDU|RR;n+5voUA5+h;Tks2XV0*@I(Emi&s|nWeSHer376`&`zLTiVZ9 zU6IvTo@X_W4cN7&rs@F(qt`t=$7G5QPh%;o2bgt^z*w_2ue?u$r7X>D+}u02te>$* zd9+tWzQr^)XxAABRv}@!dw4c|y{gQWqS53Q6{@5pbBR`$8mzK=$<`iTdv!2Xrzx={ zNvfivT#ef0Dif0jS7$bq+X4Ywc|&G3{aKrejcK$h;L8hCr%2v#^Blj%)NAr(1BYkT z)#Wq~yliqWlg4-Du#iugS{cam1*)^KO-j{jTmnhYst)*agHN^|>cCbz|760Pa^jn&nS`RP{C(|@J6kqb+fOmA7gVFd8rlF4b8(2t$Z;~#m1bcw_gLc!k^ zk;%hE#xLA?B|M8}S#36J7JQ6$4~#4DWM@UQLjhdYWHJUk*`Wf5J(L;%8MF8T;c#9- zDBBa#W4TMRqz6Kgyn?)fi-MVH{E^25pW|G{2y- ztS~vaI522~e6V7m_c~TQ0 zISw9L%#zuj2GcVRnPJ2xJ0mG65kdjI!C+=yemDvHH3#%uPk_(90w;a%R{TYAM)4y& z5&S=F+3s6%kc93H{oguLVCiHE!e(OEg3MMqW^#-VOD@k}W)}k7@Y2Z_#KhF?4&YR> z$(;b?lnD$KgXprIljpoV>%oe#!63AWN&2uSCtR4H84ma@X0tJv8g@7fL%E(H+R)+; z2lFF&S)L-+k;b4WH#C_?fzePEL7FHorr zYMs_$bEQ?keDa^xZRj&DV3D?YBLTOt#U_ePAyZmvirtDM4oOyfN@|)Z)Fg_ruarqCA!lHq)$Q`6 zxf1c#RMKR&RuyH2%V6-SOG15cCW0OKf^O>k1XMqc#+BxAxvc{O&QMCyKMYVxLFk#9 z=EJEkE6#TbVp%w|s0uDoF)=ZpH3n-61I! zFdiP-JO;qo`FIZ9pMjXyij8cwJWsf9QD)>UPZ>-aHWRw+?J?5%|#p5COE8Deuscu=$Q-cPBu!yLwdCuc8&6}9_TH!YW+ikbi3PR z&omo#YPHS?Gcmi#Eld)mTipgHY{cTPGo1$at&;FZy;84EAkgB(kW%0AN*c~gCA(Zc zU%;P%(G0z+udk2kRlS}Je*mYd97Y_E@0S1W^oR#fa-u-`MTvZA{tO(F zhjJ94?npWk;aI8xx>PU0#qo2nOVeqSm_`BzZwP?}wv@CXNwYZ>$`viqsLiHKM+!6z zNd~ewS-tU+*Jhnzuu(rt17p4JNF;C`S8IR=4-z3b&ja-eJC~6WkPR}$Sq@~X)iha5(Mw)M&F1b2HKIra5$|9t3S{gcA@3={25f2& zb0}48pmM-6(1JHOq-?U;pl1QmR|A)gIhkUE0@c3;m{>WT~M^my+%GJJuw zu+O7UPIagG0ui^*1&@**Z-(E`IuOQ|`m{)0LT_Ccff_VfkAafz&+wPPsfsGp#5MDHHbQ_a2TU#8iOAJLxx}gzc8-Ze{J32cr~F_- zJ|>)*&KNY4KRvUhXK`g#HvDWjbFx908;YwkyF#`9<1 zRe!LAeke+2ix(_KPHrTU;RTms@n%FKxjEojyq2jcuB>QPSzUEyc@FN(WTDFPB^4Dc zK+HMO;VtZd(TvGBV3dQ{{c1iv9+JH+5LlXv}JM`wWKu6_=T`_KeYHOKvHAg!M48lbOn9UTr3AX)$~Oii76<|)@Yn5 zrQ|wN2I5>$kfTwjq?C#i$;yzkx^GSc{Xmx{l3-q4#9th)cPstT(bojEmi}{ww2aH` z-MgT*WyqZV7H!6o)-1m=tu9>bkJRS|iI}F-B3&S-A>uEJ)TPPkH0J(uhPI5&>)ktV zY|GF&{mq)dVwNtoAzYLZsmlu>-J5hp*wLeJPCZ%wOu9vK1d1=CKj2BUv3kvp z46m0+?>%GlSnTXkgv>M@^4&+2Bl*n;5!p{6Zt8ZHLV}B5$a?L#$CUj-)T?&NzqnH* zVn-OiNKp#s=pAHla`3#2H&&xt30w z(D!eD>pNjuY{e^EW=w4BGhy0_Ygz1sw(ha?+E=#V6=E?T3OavIE&$va#!8KHnt4ghyo@NN8I^LDmZN64lc_v}uTpKVBX}oNT>jOYg=fD0>aD^z zzhaMXef9MjJZ{+V&kY;sn2j4Ykf!x`YTdBm@(t3VU)Is@mbWZlw{Ge1<@DS2|Ni%S zVqQLc>AH1zNlfd~?-+8&5d0rLWboi2_zoL#=a4(`AM=>tREAP&m!9VB{(rlj%P;9E zq4M&1Lyy0+uV3M1bB7*3^Y-zf^ZFMK*!L!WS;U!rmlgKI@7r%3Z=N@xu>Zby5h4Ah zrRV0kzpVIVO|&Ju=jN-Ht(d#HA-g4e^~cM8p1ZkcOLNanbI&jPcy)G5v|-EK<;(Cc zyCrM&$16In+T0UWKpl!8yS+m?qgabToNeaBS?vT_mRa-eVpk>;2Mf%dt#V(h;66(e zhyG=%F3VN<7Bs?F0=N|e)CFWtFw4wMD|;n-l|whi`F)n7wBF%xgd*8FA*12M34<|| zlN|}+l`|O0&dLls?BWTtDU_2lVB~2N@i3rhvaPWNM-RYTKdgkISR&1-M0 zxbx9Fai4X}LSHB+A=v5*@NUU=2JzP7tE${R%-lS|-*fI>?grKai5*Y3UXah0%H7MY zBIK?U-sv^2SFdrffq1W;1Y^(9_v>+?=&w9P`|!}l>?E9PBw~_zq&bN_n3HmH{^Qj( zxt6qIM{S9-FeMa9DRh?9I*QXQWWjH~7N(8w)oXmu*oP!kPv0evlR!Ov|5N&IJqg8& z@EOvT*t?^%m!w(frr$(&Dmxh^6oe$ph(rmqy9zzRk|YQybTVsuf9I!=yUy#@_Svwo z8OH82O|(4${o!AbAcC*JTZ=a^Z%)<&mfv_MTT@&d5#-%<@jKBzb?elrTdDME&(8$$ zvxZM&Pkh$%Q{jeB8$MGROy0oofS0+M|GkIU^CLo0x6kK}hDL;=Zm-uJ6$d1q!ihLx z#g=K)woHwE_-O-2{V56JDb~S)YZ5?R2s$494+P}p-!DQ}=@>oH!q)Ih*cxtzk75_j z>lEXxz(Dwixm+;^^aWMVCZSS(ADW(|DZr^AlKz)X`^H zNc_=ZQ+1R*r?jW1cf8v5>`if``y9&W$~sgwahwy5(&c9wse|NcVAyeguL-?+O)$kn zLXUK(BhmzMmd}UyCP-Atafjc_F(@4!`<&^CXK}pKq2w9*{2i}$J*SHwIPE?)Jw|HP zUPtUFhP^S?!-03CmL9`9v?ozyKyUw$@6VX^O zHQTIOxX28+E0k%lJ<76^h$E%YpQF*gRxP;$4J^THP@C`s#15yyx1}j7+yQvp)LKa! zeb=I43EV}3@lBRMN=;8GQQBdgW3rKu!=4xRtCEkEiO%$zbeB|i!W7ELvpYg+GttvW z?aE?Tdb+DvYsb;{AIxe7UurR(D3e?OcZy}ll2shu;3PI&A==ljElEj78w${~{{(q? z1t_c^7EdxN9=M!YCqXb)SC&}OwVuqgdRh-$hUXrGtwqW z3(F-=}UB~z8Sw_{3jAIa3`{C6y$iq3Xvx8y<^t(=b#!0pw;=ztV)lyd9^Iu~xm<|5yKG+X1 zzq26D%o2e5-6qT1p^rUk4FY{De5I2;b6t7dx>WaHI z_PTP`FB4UFBJO?hRpCeF+mOU7a5kvCSY0gqNY5^xRJ%xgl{kO+f#H5#JRwl!^KlsX za|n<(NY?c;daY1CN5A>@TSaFlQHZaKr<8A-BHHg2?<*80wf6f?7$_(Zr#L5`5Z_fk zkGOxu3ykj+168SHgGgFl5Ckeqvc>^N+2@xXf7=&~+VeG0PJZ1hKT-?q_$< z%5Z!dcdhp2Wy~;&Jm#`9Upx@$z{3vCqnV6)1DpYA^d`MEwWO#zlxuVRdiaWoZ#?+x zJYt`Bw>MB!)=*zHqP!}YWwBcAVIO=tj=q)5g^M0jio=!SNP+7w_+HcNO{S39l4Qhf zQ|@41QF%G>Odqpj&!6wkJUOLf--yPcC6zv}%^r&86qM9uX5|K)wqMB?6iQ41&GNSR z8vLC&Ip^NJ-rdS?>HZ$=0CIGJnZZ5vt0rdzeMZw2H_n{BL=ob1>?y4KR`?hW@l!F~%9kh}U)sy#zBf1#ErgsqRyWR+iw*&Y*P9u}jhvZY;4qmzta`J0t?pEy65(i0 zVIe9Ju)tqh(4llWtx&5tt_jrFRP3)af>UOQ(jqfQ|q%B z zySW9`H4V2~Tw`{425q-u@%dlPRCTlvT$KXGF?mAdH zCfJap?V@=7wy3kF?YDsBn~OZ;wQvLin&Z(fi3 zvYtgv2PYKN4h_uef9CT=!u$U1nK~YGGr8~vvK)nZ{eHaD8$RO#c4Qj7uRv4^?XaLX~ob+P@ zCq6HWg3*O(3wbEF|q>Pw+-EiX(l8XSc^HxI64WAMAqTg8u+ ztFX2!n2V2##vjfTvcoM2El08V@huxxUp1$qqM~H(?6n(i8Qn5ytv@~8->bfP$hfIh zWmnB!d&92X>#tidr?M(iR&;vBwL7+5yJF_F@^aRm7xKzbD4YfS3?iBgjl#~61n@$p z?wmbCV}CbpNOOHJhJWp#meIFtSUY=e39_DZ)#?pXBW2~&X0Et)+m35joW`APRh4rV zT)ScSuIty$zOuZE3X{L@xPF{M;;|t{e_p4T!FNcl|gR*Sm1YnyFpj`QC5>ct{~d07gkp7>=i#KE;-Sh@oKsUt!V|KLLYn>y+P9<)60Y1N$z*K_b9I%gkj3dB~`x6*1 zf^z~)OI{~mQU?wTe@uOGFplq)&Ib4tICTM^B+@xJ60nclOvgSY_7(eew6p&DYiCbM zRKCXGWPE=mcLVGu+(bA2DX|{|10W$U($7VWauMc<0#@7+CVLVZPmKJ>KSrK7KJxF< zvA>Tz&g=Uk{U_kqoqGy)V>J^>37cg&X%ZmM*D^>#T(n(mSB}Tsz6#vAm%%O?!1+~n z*D;>3*yA0$#Zd+4$@p;;i|w}@yk_9koSbP**Brd1a7sPE!eN6 zSM=&LVt6pn>x$BQkM-;s&AKW-|H_u0J&)b{@{sF3*|O5*XlU5_@ya2q8hgI@?%I;l zRWmlc{bFM;)|SIazO+L89I|WJKnDm+ML}Ga(|bQ9s+dvup8oo&uz}u7R0jw+Fu*TR z+$4>YmNQ-pat!zc2#KcHl5)gO_RlCs>NC)looP4yX?Nq@c$mv4Ogucs$YeEMI!%>7B0v`(tQ zU7nBwV9GF($uEoGG!PcjkbFgO0<~6v#21at7hAYk!MrC9X&wBC&^MAT=7?W!P{S3T zeq(H+)$fLrPL11d74F=qhu226L67s?7PxjY2+xI07Cn+^@RHfPzzK?elOfe&!uwR? zM!f}o0!?Pbam)r@#$n_L+A1vbu-G1;t@^|a!oOf%`=an#1zaw$hGKQU2KURdn_3mD zvq}LsqT`I1Ne0qG!o2;z!b`_Nrtc{u3t@-PJPa}(-vVeH&c+QC{0mN+r6gw$AO5bj zb!Tp_@GX5EZI0s{LMFQw`oi}hZKp?pZy4E&@+G0olX3qJ2n8u+T5yy!ft3IDS$+8M zYWivA0}p&QeE61VRJ?!EJLAT`Gl@JvhhO;ev9Si@?nk*EyfoeFn@7^_=k*m76UhQ; zu9SjRkJmWl)Cxi}*&o|Hmp&+&&wndCck(1G@E@cPq8S0Tl-whYkb-e|b;u8R)6>E* znnIrz-|YwqpFQ&o;rTW9V&1PeKaa|Bju zP1NZMAj!aPclfx{r}=P@}=3F&ir>AMveog z7k&drsp6=#7rwywc*Yr>atMbAZjSYb;OS0ckGv$##l@^GKsvjWK!(F zCh{#S&dpnC`xf`}i4w7TU9Najx=MUN#%C?{v-^s15p~3mGZQ#95xShbXPitv+|n>6 zc7~jYomnYlw$7!k!fi{POX+7z>4}?&_}We9&of-h74J$d(m+_*n8C3}Knu`F?A{{Y zN@n5aYC3lSd8wIPF@WB5IVqxlrDgA4y_0-%HN9ykcG3N>CPk#^YPtcqS`@3KTBB(5mHu19EeU)(iFmgqR-qak9-5GjxxWJ1SyF*m}jKZO~ zm*q75{DfRS3?2a*ofu@?g$bPHe%xd%7czl!@4T=uGdzqe2-8i&Vpp|~6lRk$`ciDW zF!%hxoF=*n{}-QsYB5%j^2KcI;trHQOZCzpxkQICtYFzMX1n5hXI|zT)64pgZk;}9 zJWMY`;c!M%pRujeCL>hrCx2&Liui}Bvi{+4IMCFuwY6>X*x>`=KoX&%9xLJdX2ErA z4rmpl&^C)jSom=oX~bPM8IW;CvG>Ahqhj3W-0fQ$LG#B+o*HXp1pXv1dDKM?;{`TX;1*S2!S!X8TVKtiSCiH+=zW;% zqsh%%E6c85kfFkBoZ;C|M&*A&|L{4hvj{qV3Uqf?oQ`)<@lvH4t6j}3+$)lVUbv)*+R~D0W5~)F0ER=t*S@ez<`~ebNT#@@cl|Rv*VQE zXxQU{U5n8}=BL4Ty*`ELL_>O=>hYkeHp3tgE$m8QZbas%8(_TX^M#NkGwh|CJZ=~! z`Ms(1XIsYL+S=+Zayg@9z4QmMH$Q`;;x~%=GC@ndO zw!;9}0Xq;{syC*l1k*#I^k7P=QBO|7GQf=C6JaDhy)|SKpGkC@cQcEnfaW}*T1Tw>;~zU z`PY|KRrOD|oO8pd%a`tP(m%LyJ4hgs;qmBMS~AK3IX3Dt)J;%$$Q9CI@nQIh0Tp4A z{R^}VwP5Z}SOsu{TcR3_i;6#cN>frz>FEKeDhspLu;bBdaz|%nrRQ1TOjzvg1utpz z4u0j8!Td?s>dP-SdEjW*k~*xmb{GumQ(*C&?@JE^v$8?~-|=zdj{5?ktgK)_9o@$Lm#U@wifW%#aN15?r%N%4D^u9SXPn9Iq%y z@U49lY`fr*TnF*zV@eag#w6s)iXdojV(zzrP)>l9qBQVl>Oz~}kp*z}@dVt>a48%lAZAgqYDmyoLF z?KMM0^Kx*w$wc+~CfZ9Sk={yCI0#E>C4G;z0;&$rgX)7SbO0RrAt%;m$2DT2&AvpN z{o1|FUQe_c=Au%qI*8PAgNhP;Pl<^wg4alv?!f&KR(LkZX7mRz0X_pT!1D=HN09&< zAK17cj;pxwh{%X^$Mm|H<;|L!#h$V<&*B10KK^NvkOG^4qo$3+RdOTC7_AM@rq7>kZE9gOS zk17lerUIANMuK8k!KH+d)|5d*g!(vOFTY3IRt~=egv^n|@m0C&icfz)A66%mwC3J6 zdN64iX?{@rY3Shfg=YwP`L2$pt?%`-6M^9`2mal0{H3^LFBl0!3x&y{W-FLVp%#>? z3{r0E-AvMw)%4*HP8YAstr`!*&pGhy+poNh9^5Jrd%yR#iihudnUFJu>jw|*NWz|G z7!*xdYiU3lt6GRB71Ic5xv&LWjUQ<;)sr9SF5with0KWMs}`Pr_x$Tpu2>k;bZik> z*>0f!5(lU(Ojg20IRUbkK+O7g{1H|$T~)_byp1k`W5OZvGWz!e5PAF^a2;2P+r;?# z(p44(91+LMkjNM7_bB)yTrAy;F#sJZy z;{iAozz=!y0Q-^WUIGU^rCAw{#7A~r#&B_bFYVul&;0rPXP%5s#?=iiM-3g%PQ`<` zo3_QIVmAkYPOCZ}kxs_%mQ+Al<`<#QyGH!D!#7WQHb}mU-7cLt--DIs5?Jdcu!43R#vTB-b=#o>#;(#cm^=i}dx5AHeq-G~?F;h*&E{MJ1P?in#}#mnT8zI|}u(#g-{++lz;fxZ>lLtBCZ`RU=wrrw2Ce*gk0Bz(L!0G$|Xl|C;^G z?8?elPeJNCo$SfYq1VOky>-vt-2~U-?Y?ynGEt16Bc#QsFXS0)D}l+xq_<2-$)%ZC z%EhPXx!v@q$8pQI00ppdbnCsZ9Bs|bQARqx7OlU&tvt;x=la!oe8$YZwY5xV6N1p` zkH9Hl*QyA?fd%+~T+3Q4%s367$%B8Q<)^L?l4hSeD0Fl*D^Js<UlRe##S>Mvw>tN%^gm8a$E)9rLOotB$Jt`o+v>eJWhDPDcl z9}O?{Ls=p3wL*JuhgZw>Cxstl$tO{-y$52IfH@ABRB0lY38R4+7+KohF5DrAv6wWG zR_>H(Llb-kU5_*WI<76tuqW(m*@X>e6M7PN>hb6?=Pzx7nM~n z>Ho(g11Fz)|ImSVuf8@T_+(!6%*(>I=|guv2+2BIYt~~t_LG*P-fTaN(}*gYqo}Mz zfkS>mx?m!vbWDbL4>`+(Kix2X?AnQRK6&lub2Rsy&=GrH%~<1TI@IzFbXyF6Y?+}QePg)7&pNigi$Ed&41Bp7XB%=S=0hHfw3ugNx-o06<<`! zvMjhd#b^@R-d{t%zLkExMmR5g-tnY})q*HCQj@e5^QQsoc@9Ph)>%* zF(1PpY(~6gO2Cb9o*RZD4)MpakB#4Y-<%yYUweAZ%%iIw-?nOCo!kB|{y||Qs>#-A7Op%k7JOSki>=k~F`NS7H zew=ps8@WA)4$d4pFTH8U8I&Vd8u`*q4u>&_P_NBz40f51t>bsbaw58#CF*2Q-HAHb0(*U^`M z3ogXU2ND-A-@0`uB1-q$^}wVP&L22HA7fCwBL5REUXlL^7q7_wgo{_?Kj2tB{N2jO zN{BI==nL>#hy`6Cht~;q_Kw(EbxbWFJj24x8` z3Rg@Hlka0|d6TnzS}?zsDL-TUB)ri=ITnE0OK7S(*L2g&?M=$h-tVSUU%Jf z$v6-l-6A&98((+n3;6hz5-P zqslj+k5Kqa(}nog>QFnZ7O=U?Y;+A-=A~B&gALjT+f}-|g~;9H*?n}==ac6!XH={m zt^khPLFfMyhtmSrzb!WUN7CY@e-z**a?MtiZZ}!Bo22fd|G0hN=qD*7nndwWa#H*e zG>EmO2|C77li!|B?p=7#Mo}AkM0|zP*YZf=8$$ZK0B7)u5#o=avA+!uH{A*NKg;mz zv0k(F%8ta{S81?}d>EOfer$pM0~YAmTPIHnS<2I0OSABNtdgy20wb%)`#5m9v0iu( z02c#t$#HNms`l>4#Yr>guH4w(Ubuh$1NSrZj{&`Ku#3^u||(3e%4#3b?h|Qx77+ zX@PC|!0)fe`rW8JZBdEiSy>dfq247bAJ)lqXm4#YI~OiB2VgbXKqbnj zXrWI@J5W9xw*vEnLC*#=hVg8cjV4F}$%n&ZmT=ZmFRemzZXq^I=C`C_D7LO+ql zV=OQaS8^IG+lg+m^KKDe+qCncZk-_{n40nNB3^PPj)FHHO+O}=e=55e&&<G$j z^Ypv#o__P4y@Z~kpU{uFlF;}0nP~o&!e!gZ&b9rqf(zj06%tlH^o>g~s6J}bIs}X1 zh)%gl5>6;?m2TA?GbO8BT1l@^5y_~OIl#jToS$wabi)dKd_5Qiu( zGxj#?dpmfsc&WMy#mW>f5i15S591pXrIE_p>FLP>Nr=8Hm&NwWSIVU*%;v6=h>GUU z7HNe#1>>A)8Nho(LuZEYjR|1EQn6hH&RNTyjvWY>zA2@skb?nzK5;wspA2r#`7pq0SBib&|86;&Va}Kmqzh$77tHD`XM|$Y8#)EpkqjnNs91`fLHM_R!)THbbcy6$-}u_ z@GtT(cwNN51^D?qoX^7}5XL?R_zHM9PJ`ngYtP#)Ze;H3-#>2=}+Q;LuZ$pUf)jWKm{UK;T{9eT0$m45x_tP83!)`2@FJsAk<7E(5F(9NrH+PR}8eNCAx=v{j zZ-kvSTdRlG>m|hpDnX;XTq2h%G^RH?_)7amkFSaf6ayYMw2b;Q6o~a8tr~@<^XUq6 zdBteL-Vbq9EO;-CmAOC!h@*Mp)FNY8HKd3wl&gE3S*I_b>)?_tNh#Ki-XR`HWx5jHCMupmu z0w2OC+Z!j$Se>w5ncnEpfo3r~;oi$xDL2l5ht0eZyu5r~g*Q>Y1zOO2oEpcyzPOtY zzQK)Vqs3@7+KhIi!{{`oB)L)*aKW17N%rWy2A|Pq@|k@WpVepc*?kV5)0g5m;ubBV zXq1eQ%`-%aq;iFQl27SN@+JH9i3BOEw%n5ime2s!%_6=#=B8!ETwEYbsdV|01DVUG z4-eK9RyqPkU*>XQT1!R`Wu@PcRFtcly2#}A>XVDJR8y`tq0bg$T%F^6HseuTYw`c4 z&-kceeSB$O>d|GaA6XxYm~aH5IHB;_J)g23BO2ak<Gir zru**Qr2IEMckm$E;X?j1>TwY>5Q$3CmH&yN_;^6|F3l$~v@b1Jy^r;;j`uI?(NvN3 zC>z94F<;788pjb_Xjxtik1(%qy7#_KuS?$$-NAztln3>2lYdLC;!MVe)$1^L1xZlg zR0nGi-XiZ|-dl0(tvE#r0(Lf0&F1ZxuUabZQ_q34RzYe>y2BaZf)p6xB;8KZ??}4Z zc=@pADaop(*DP6jbwzn)8S0)$qgVJ2sufZ@5$mPpm>SdY6^>~@(jok$Mj>TMGg0FfO z8$Eo^3yLRHlf}hx9PrK>5dHX)h0pH!ocw}630RCafq+(vJFv$KGRsWZ<8Y=8SC#PN z@sKo?f`Mb|P$qWbjGLWZwIV!t%xWu#$Hi!nyHkWy!{AagpcQt+rG!G;yrytu z?5j7^Gk@fMVk#341a?uuEVW zEr;WO4^VLhq3)OLDgN4i@#BR=nwNTi4})wU3ugg7q|Z%ixunrk`iaw#~44gjE2n zo|#=Tw&Fd%S%eJ@Ls+nckpH<9y6}T~V5) zB1MGqo-O9y%iThyz&eXDT(;z?}e{xVvcN=w=R0_=>S3$ACcu^I^`8A7?h{lN+d;HDGJhOy(bY*G_sBn^=4z0-Vj&PE~vkW3JjU`#UC!0Y8K;w&?q(@p>a|Qb@sjF|VtFNzXuYWHy%~O#TO>Y>_ZIWJO-_cNeKqAylD+g)Pj>m-3#}d-G*vZErQMyH% z(IxGZW}Lr;wW&rt1Pmi-XX<^s=-ChV$aHMYlQWmP1b5#xOBY{B zNM-fMar)KJG_xM}U@3fbxwL@Os|sM{R`<>55eg)7~H@1A2{InOn>VSL@Z& z?(EodX!UkN{xWm<;WJO{?w9#6-w*Ys$DZIfB4Ct*N?xOENY)b zgcG|yAi{@JOGJki;ubbH<#Hd0+p#LF|D%BM$u;V~7KqGblU0oT_xyzhc{WRzlmT*| z|ASH_7Uus^lEsO2`+t>2tWK=!Lg&j=gFDAm*dt(1Ei=zaeCYCn^{_`%!p(P39D8iT zs#Tj#%+i&%7iqHSqx4(2o`3Q^MW^sI>2v%zeLVI~RlgPM7OiQnrH}q;tG4~Rn^>C* zoku$Fkv56fz}GL<^!S_r`^J}Wxai{(LJVKTOqBoUEHR09^GPuTqb;Z3Z8QFG@ZP)U z{U`{*_TV+GtFLW&vY;V+VUqBLowVmPRhFg-Ek(`2RC-@aIP?Fa?R@~VoZiR(>zw=l zBN>vV=+PfWt0u`xX{%KmtEN^KVXLjST5YyfD5W-OH z_d3tBrxiZ$&-e5B{=VJ4_T2Y5*SW6i{JGCL_x;?@xsSA z;>6xd(;{R0!rf0Be`WCQ_4c3MI?AKdUggn_`|f;M{V(oXcSK9(`6KFj6&GB8$HZAb zE0t20dUrxbQT9alf@tad@mgP%U{Cq$`rUJeEjup#*s;pGVtje|1%u)`McO96q1gSH zeWhL*`QE{NGaD&`1NR#5VzVs!%KTwhExKsMdEcH;cjE1RFUlTxOTSJ->(Zs^>Dr3^ zCk?Dr2R(SzgIBE@9N*^ndnV-mQGHva?Pqe%9&e|UuY*``XirTu&PQe?bnYsWLB1q1 zCunTW5bdS(RnbhQ4or+czUP{;T~&`2-Jg1P_Y_rr`oN-$T3&p&2@5_rBmVd^ubM=8x7+=T{Z{1n zI{jl_S!QZNN7*HkeRI*UXOh|6)kM59Z%8x+74aV-H8kp^zHR=NhtIkwefLKL>jo)Z zd+O-Q;;E@8weK{4f>LJ>&s}^Xlc7}v#p`<{8$se{g|e(CWm)wOrc&pqv)uG#w7(}$eL z+mQP97&APz^3j^POV^(|rt>L3J~rY>6dPOFbLK7@TYt_0{eP8?<^o^jl_dw8E0)OT zu7SIh^Q_OEKW;ijQ$+rH({}T1ll|7NflY0kXCsPY zeR-bYJ~dwM=9d81s(kg0Op;5vi&xFJN0VeR`wO|Jc%k}+=|WCq+riUIU6Egi#EabT zp2X)Xtc9|Gd(&eHok8dfQZD4V@M}$vKx^zO%ha1PNu43-ID9BtpXW~Nd2HtIT2_mD zO14Q2TGpcHSy{k+&Udl9*4(e;o@AlCCLc4Q`PkgW)HZPo<#p*w$jgdn090$4h5yK^ z0je8&gLq%YN2H#D-wS!Heh2p2N4DqjrDYTJyx6?GLN3haNAfU(Jecizj<0Rrx)Qq@ z-&?k0uwimxwnv(`1(7@~ARlJSp%m6OZ-wNn5bKxjVIeVlvj9Cly!bCnB5ZGr9ZQDd z(<6VUsi|ovW%(5Lx3R6KWZ!S0={HJrZ>#a-Z!LLUu!nT|^2OA_Vik^jE{v48DfK8l zshb!k?Y}|Akx!G~Wz=4bwRqfy*7H2qd;QVZU(P1SKKgEvsz}ROzI!y{h05~g<>%hN8;Mq1gsQYka{_+#Dyb&A}?Q+Dy#T*k8|hw;0l2WZdc z^94CyTdJ?rG9NYdV9L(q```SZv!|AXC-qFpo6?MxlF{~5By>QeERBp$nZ#=M>E;@I zy18~@=@zKMNQuTQni4f7dA>Y|ep8YMMas(PF|8n$F7|0kw1&45T!QsVHdA&z`BwZ$ z^t{Gg&1b(aTtyk2Cu=C@I<%VhIfv~CxtA?jR+9QWN_-AEm_(a4E%YjR3C%f#)^LBP zkZm%)SMgTe1$@_XAAhUaCaEd3iyAhgZ#90KZ6-B(3H5yrb(T&)nU2;MSOxNYRxfy= zc{@km!fqe*y~^48E8j?(n8P_M`|v#Kjq(`lwS6TYQKyTs`=Ux^`%2x&b{cPaT+FwG z+tizE+tsIRXR{rnj?rDX;REV%HWPj_-?;bW0p_u)mN)+7@H(Nc?4PL)LOwCJ$vf&w zewX$U8agVjJtHXwVri_(L1!m5R^H~_K|R&G>PPH-q-L`%QyWydx>NnhiqU7QbJ+h) z9>>x^bXC*KJcu7-PK5QwINSm=_BZQKcXLN zr@m?GxcmF2j!lp4E^T^4^`SN0&6(SkmavTSpFw+Fz>(=?qvz_2v;foQX3%P8(C%Mh ze<(G)mbAyScLV3j0*-H_eisn7jc?J`^1G@#2+iXBF}>|=NM`bF&?Pc7l4?OD<@HE) z+Fi;FX&UXRH`*6q^=9+^rsT?e+S@onjfSU)yMyf&juztEg))Xuv(d9QJ&XTl-<-+Q zn!ac4Cwg~|3;AnuXYzL>k_SXWO}=b&#ByiGkV1YRa}eGxkTQCUFfHsw()Y*bOKD$k zDMcGQk8cynHQP4Y_<%^h)<(ShjPw(colDsHXgPvoBR4{pN6w1Qq+iRqV|wqWc!DvN zcDaoZBNay4tD7iJHEkqfC%<(Q5kAp7I&_86V*w>@6bfm1gN}NUt>^ z>Sf}iy}#)%qUZMqtW=2N|^D-$e4e}u>T0X_X5sb zv+`Rv*(tx8pBVC6$V}RQKgRg8IU9!Xv-SRLJ!rq?GCftc5;jB)lfTq3w&U1FvJF!i zDw%WWOj71RKSGA9Go^{J&MKXA=1kR@Ul8}Bh1L+4!`a%8bf#} zLyu_oO+RmHEXH1=VPs?+ODm5NEB)A~DcKikONQu}XvW0>5n|(EtQU`siRLrb!^b}R zGM6#@+dtD{45oLFjg;ndZKPKD*DQva7mh7Im zd!p(?Z}KZ`?`Yos$oDvrw6(ixP1?v$)uZ#H$ls<{oAutxZ-0;9cia69I*06z|C^UX zNi!+p%M-ir-2DeXeK)x(o{KNZlmP$x;7XI(?L+D-l z(F+}iWHO^}S3XT|VSYP)9Fkm|69I_61c8^kt_ZBLvDiOQM3du`{+ z6V2OG^s}e2^&-|>BO#^RMy2^2#__R{bmnh#uUXGt_HSlvHQSz;z2Zz*JNbpbzwEOO zVqP{R626bth_p#z<^_*OMz)NmKb!uPi`Xu1{#(r~%lJA;?&ilG0~vkH_7vlXna|ZW zZx@lX6Xa=Gts3~7Lz$i)Nfo^k{I|b*$DfY;DSwk6^0(t0`rYW(k}?+3^4TI~!v4)} zENmpt-R!$%(WcGTEWs6_-@I=$#cagV$BwfkgZaiavCXu6gYGK(8%UW)%X4WlcgrxY zIJ?pEK`Uk&g@m6^Yj7o9Nkqy>{@d2IIkfpRDjogHH)F11g-;}mZ(Ysb=J-DJ2SW*8 z7C9cum5sUQW42MveS)jvBU?NDn`+m*AFqE^@w$~9s9W(jj`y9gWD>1}?6<^KFwS%=1pW?$MN2hkruO03e%GQb<3j-Kg4G4gZ6@PT#fZ(TTf5WjTz}dT$%OY zYTcI-=FsM9xdZd&WcuBsz-+CV)f!qcyYSI4f@_1>Xx+fP>j*+7qoq9(?IWXx89A28 zb@B`=U0lsI>M*W(2Q%w=pKJ9Kkm=3Ly(cs6Uf4JUZ_Xxmtdz>H0Ko3>M7047hkkWpb^2o*Sp3- zhqt{cvo3hjmNdO2OlUhkk0JC>eCk5~KY-Fol5V=adY!rV$1E%++`pSFP4p5y=)+Rc zvt72UNvw}H7=Pbpd!6glSJ>LgAFSzF5urOh-e_{uhrgpKL37WbkMvO^`CGtt0`+=6 z*ImcJ*^a*i?{GMb+#Gt_13GD36M%=@1IzAdJv#v(n15qd54&%H*j z^v!*@Ww9&t|Kc;7-)tn9jrqcKenaq`(Lj%0#bZ8k?B9ZabNKAc7W+2}OaJ4$m9+N% z`5nrCyKl;MJ#(^-+&?hqX?t^LfO`fx@-+1^fL87DX#Clnv(bO_E^Oa7O^G=l`Mi!= z?id;CO^N0-ZD@L&*3*ZQYe$QW{^Pk#j$5c^pKtOMpBk(h?)>iLxsF7b55&2Zu#uN{ zw1Q+{e&`_^gn_tF0yOZtV!{!TR&^r#^Hk^lgtcAp*yiMv=qk1D_q^ zM8a(V`$w{WWHu}U(sd%dQwkv4xl}kgpo*K2@vuhZsAP#u9FHdM=z5WaEH0Nbp_VD; zN|A11s1`{~1mwFD-=jYe*OR!OE0|U`iX699q}N7%!=Cw^^IAOzkLq05nH6kNYL`I@_B(fvXI}$x3(L0j(k*h>bv!Mf! z?zBuG?Pv`o}DVbwJ$MQm6uS zjokn{MNV%6iI4{4p#l~`Ev$x3u#FpZHgo{waXK%U0s0J_Jadt43F!A77g zcwk!2h=(Ldhg_(HC9oXUz;=-{yTD43@#r5<{CMKWqi6g^XcRds4iX>*a)7jFXPKL+ z5D!U!{&UcuJ09l2Dj=V^TVbb2UK=2H4b`1CX_-IpkpdJr*4D> zF-yryaX!?GOsfX+JG~VUHhq&wNiOhNngUsX{&RgGVOcy>h?KX1^&%CdtEdF>Fe3-B zF*6RvL!HPh;%8+8K2)NkG82{n^0Uz~I}tdZ&GDRK*e-G&Y0ujvG8fso?9au{`N*AL z2HuptcnVL6cYLTp@!y?FxZuu9}2WG-3+ja&fd!$y%yl3*z`h|EXNd}QVmH@^aq zonH&9VH0cQ>3a5Bm(79MgFSRKs``43w*%m1<8;Fg)k4QVI{1GEkK^Hh=T-3 zfgC7>DyV@v*a!{g_5s905~M>eRKgNi4r@dfWx^I{6uB}E$itO8M6ODMrLY3l0r|a( z@WpL_JS-;N;(VA3$Sqz48-TnnCa+7dwPc&f)qGx!oomJeHm=P9!k6O5(v^Vhb<1Eo zk9cD9dSq`%fkN0MQk?*`A~*Jibs{&F0(x#H{mtlEmJjPiZbAMQblh4ea$B)T4e4r@ z17Ww%gB>DwsVGk1a;0nN>hjM_tKeR<;Wjc`VVe~$X z%)|3x9U%8ef2bCDRA32g6Iq4KD)c-ShFX!wk$D{XC$fRGPc(?s5m%Q2gg@CEkb8=- zr%3-adR7y+dV|O_RU*%}fi@)Ax}RSPn?zpd4amGuFS0fs z5+E7K$6C^?MQ-gzk#&iH{&ibLUQB^fm0LiQ!nzElD80Ua-+^W|kC z>sP@#o&XTY26Vnkx>x%{HPpdok=F=&4Lz@A!gwf#xv&V9!3wAc>~81}#BU&e1G+bC z5_!D~^oA@T?sas(j<2sH{|36>NCe{EAnpzF@y1fX_8XgFr^uTrPzr>N8Vk#~K-=XbM# zwC~me;qQfE9+2ie(!94C@bCQ&kPP_pekmaHJ~HpGgf&nP_*0MG`Y<3{p9O_b2~~i6 zeWS<+$b1kF39ugOp+V%s6d=uqxq!|OH^LS`??>eMqY9YM)SUgz?0<}okCFSB^dBSh z33@*XLo%S}lR{_|`Lr08i)_h+@vu(hv)-^-pi}BHv-_J8W!2?>6GU z4+D0;N7oN=Pz==~KemEGk?l5Az=j15x*N=fnXLIcZ&^@mJY0yVG_NbA|K8Ibo= zpcWcM1><3(s1RvFt3~ZsDymgHtblbun*EXAADgY?APh;61-XFC0d1fd=EE{r1zY(! ze}7mCwLn-L_6{WMKx`aH*g*p5IA}FLAi?Ir=slQxA6y0Nc}0>9DNq5+VGY!aI>d)$ zNQX)w{UMD!s*7yfDrf+X4@K_KFd%zqHS81>p9YIyhp2X>Z{78LWa0fc#;|w@1D`^6imtk9>P{wx0{gwci5UMRgE}2lChfyB%_&5|+Sn zSOfKd?BV!*co@)iI5LMLb2u`G*TH%~?(ha^6mM30p*+&;cr8 z1?=RZQ;z%8@}M&5Pt1i4KzMSosJ`gxi(Fsy^vi)YqE15oq*ADc^`iQ>0gn5VZa^34 z57|Ka0rO!QtO65{zbD%e2K+iX3kqQ#pzmaSJQLkODbS3RO@8b+8c{L=6&%ha^acT&RR4upHJv zJ!}^>*oQDALlzXmJgA11upSyjr6HGwTpDs|$fY5dhFltQX~?A^m$n5OMGc9A1W17# zD1|Dhg*8wQ+eHoaAq>fo1%)sVs$nIphb_=3YFHd30dm8T8;0C4DyV@v*a!`xG6dow3DO}KDq#sMhc!?S+eMw?Ll}|)*;9}`1=&-OJq6iQ z*25NP6m@DGBtQz}Kq*u~4b;I#Xb{D4p)%tk3DO}KDq#sMhc!?S+eHocAq>fo1%)sV zs$nIphb_=3YD63)KnmnQDO5oX)WJq*5N_~7JS0InS4R6EFZ#<3|UYJ z^Pn15!g|;OjiOGAg9J!{94Lh^)2I^tEsIfkT zAsMou5avNOtc3Nj1sX-29tR1K0y$6$RZs(Uun`&n*&JkZ!jKHAg!Qlm8bzHM2MLe@IZz5! zPy=NQYdgge9;X)<8XM7j>2oVMvB7D1>=X4J%{7Db&Jh*aX`| zO|+o{^akW7jtAr?B0mxNiTLq9Vk`1Hc(@}BnNR`CU=?f^RgegUun5T8By3Kqg?dqw zDT~R-O(uO|93W>X!iOp7ooWMmr=|dYPOXG$*et5J3lLts8Ys7E0_dBD57W>wZ9WiZ zn4Si6VVkIuY}f=lMU`UvTy&gU3ix-fImXAb4loav!g4@I88*tcLZhhiRuG2XkPhPk z9p%_8$G`Fwum&~(`pU6Y5eHo$88RUkDxeCM!Aemxh@U~4nfXvFiu-(O)*?}rq^;a8 zYBqk%A>ABw!69=hiy0Xi;d1L(Mr;|te`n#bq7jiN3>*G2erG4U58cS#q(?j^*{ z$CvqYp;6SOD@9!vhB{G~7mBLt0OO$;kg39t1?X7N8?pf%3zotv*aSO7UC{=5LpD^v zQdj|-MJQe?(Gno+O2V$pgdL);S_WH1Elvc|EGB;OPJT|@A1YxL zY!`Jk@mF(vjld#N*Jg=Y8ZYX)BtY+Vn?zmT3esRMknZ|zqHgE{D@9eO0O8fxx{>rZ z^@bdn2g_k2G>W>Jvbh-@H&Zq@uNJi|4)S3I>=1Pee%&%3)`+@QfVf+?h`Nn5w-J8Z zI#D$?a9mRZJ4M}2n%n2XYT)<|j_=_34s70;0Oae=^`dIARXZMPVY{fi5&=K%S`J%9 z-5mzv?+$~;Y`wBo)T@QC49L%G$xsbDL~USyLnYLUdc8l?LZhfR z@coTdJm3}&OGIttb7P$-?o+9^(Ek>Gzg-H*zSA3u0ehR!v1y~IcPW#1*Nb{D2`XW= zsP_|KDKv2N*QmeZU_2~`Mo~MfpkCB2Z0thct~H`|w*u1aMrJoMO{8f;e-pZz2ya5J ziF8dhPzM{KLA2P=0eZtm(Q27!Esz4NF{;-9;d%>f7j3a_h82cn$bwv0DcVkl9ikm@ z*NOJ{^s7Y&X~1zn+E4;;9GVNOV58{$(6=Aq`w_lhAuNLBupV}bZj}v$wIZw)KJ1U( z{fnUrHi>R6K-$*$(Hgz2vDq5kts6ui5QZFB3L8YnwF30T)c`)lA#)&M2POgG2UY_4 zKX46f5q*#i36KfJun1NFejn5*`e5`QOx(ewI~bh@6Mis0x9I|ebAL#;A-v57*dh85 z!Vk#;&W)nGv;k~&$%eT=+AiyX_%6hAUr2W)zH25F!hArc>uRV6Y#fD+ zqY@z<@aL#`uvGNX94BlPeM}`R0@58rx?@b(R?)`_#6xe$0@5Cf564!+D%c{r8*$yR z-K|!1BJ$li?v9QgX`*|gBZ;siY;&(jCsn`_AUGzV&JpeS8~8f$=aOYG6Gyi0<71a$%e36OcKfR&<|bqEEz5vJL$K zKa#hK?#q7PrGUx_6Fo2vur(0bf$K%5_>czkf%sJ9Q&)%{)CI6Ph_FH1L=PsPgHvEUplfg~ zY!IEcTJ(?v*ep7uL3HMFV1GDzh9fteFzy%VksN0Ux^KBr!pjz~#ZK9{(=aeO)r^W+% zrxI3NDw^vGJv~Kq3HD2{RZ85sNutYYM3;{jUC{wnik`7v^h}OtZWld^<4R;ISBRdC z|Ff|%o3wM5i9RnK2%n3cxywbL@536=7t9rXA$Be#?Yt}?%|+H@1oFXnUcI?+p70rsvY&D9)VjlOH!K%?lT z$$*Zf>|d7y_;Vfm*Dn%%L#F6z?BA3i`et-2>md4;G|{&bb{l@y1?0@AM;FZ%gL(QC2ua4h?8bp7Mk6&*R-OwM1 zZy@ZOOu)vs=>E1E2>UJ>(6^1aA4C|+MgNo{`WO896}!J@#A@3C(xC#7X}eLZ zL)kxc8LShFvC@jq2mFa&4Wwxo2ZXh&gRNp6#_?gG7OP7#;0NQ7)pZG=hjGU`sskX$cw-&43AT!L zG`5c>?C5;J$D>yRJ|-ZWkO|wxI;I%5h{d>L9m_uBjMWW0-4bC1>=Y}p6y^iR-Lt`b zVxv28J-R?9RKPM=2iwHz*#_{nXAaDT8X%5w%1Xkor2bF{OJO;X=C~xtg(a|AtX`z= zl@8eNgcr|zn%*15IsrTXfO0*dQLH{b#6tok13LR4-=`2Np$e*D zIn=>=sD}n<6zfDE;voT&Asup{5GtVxs$n_Q!Fs5N251y3*@t*YfMiIA94LfJsDf%( z4t1~|>Y)J|#p>%rJS0Feq(crALM2o|H7tiZSPwhI>PH#%gIELG06GRz#sg^s19ys*5)afzN)^-qaVh9aEfi~z4TKHO7b~p;WCHb+wj9<& zgIGh7fiy$WGnBBQgbfp@6DytiPv0O`Mj}wxr)0w_u}(!#W-F)=#S^vP>Q+1fK2;p9 zAmaFCt}o)8t`6kb7Lm59wULVaJBQzINB5PqQKvNTa}A=3n)fZjtDE<2_TO*bcchhe zoA+IQ@o{4FzR&)&=KcNTaQ$@i{{F$WZFvwmVzssO?${)jC_CWzS%~f{Nl@YDea)|# z&uQMb2%p}(Z?peE^S&eTYFqO@zcA1TH}CU10iDsjzn}Ee7dG$jfACS-ti5XNwwA(< z*YS*ViImE0DU%|ZEQL}bVM&mQJbxbMDfA?^ET{Ijz4~1C!-mTW%qBHC9fu{ z(VXt<+oXsI(^$eZmuO>&715-U=~P4o)gzGxS3wo`R@3Z5|8fe2ISEX)~Yr@pRB>w)hzV_~TOwO_*WjKwdUCtJ3 z;8ER$k+_29PHb|-%JfL9%#U`*r~t^(

uYxJ5{X7bTeTCsDbrNs8` z1NKg5a%ZL*(V8;-{Jw21S{f!lM*n|ZpC+FsZM5#EMLwg)rnicf(SKdrMrL-TPA6d} znxp9W5G$$wl-Bf)W;z!2-&i+gZq8-nf3$5DW5KkTSV+`U)4Q56Hdf~??YL#KWzO?x zInSU3%u!2@Oj^^sPA2~?t$Q+ZCO3u6VJ1ba4>h@qdSc|GCHwdCF){x+Pc5|_%|S~G zGqn`PpMQD~tDS%MWM6xKFPD}a$LgUxQm&@njU|(ly=&T>4W@66w#(?`)%=}K`I-JD zR^H(~Ax1LVGNWfgv}ZQu6FZv<*o&6b-Zd~Q($?}LmOA~*xY!B3(YlV6ax6udks~(K z=)}Axc3wt%g-ooOb{HFHOxuc%P0_P$I=w;ke2ATQGqF>&SI%Pg3Zybp<0eO@-b&e` zqnJ7S&1hpv*Yq?kWgGK37V^(gAzCA5>+ff6ORl1qi>CcX$Hhr|N-CXS zQks$)DI*vaOg)d}D4QQ-`E!_4PK5i^#fG(yt|>4b!dG4Y)uXXEMYXG=PA zVPG}~d#-@=oDa_C3 z$8c=+hY>cY+1?0JnLHTz;gH?zX*S_4R`>PFXpY)5o(<<{6#CPfeNIJpMns?S-`F1- z(K{lN%A_+TXFN@XEdGwdY6cp{kjfmH&@p^wAvc;-Q9n%i8E;1*I|3b}BA>&EHy%W5 zB3f31k;=lhkr;+w*%2>{C6hZNX}roNK9v$N>5bJ>BcV~xOqrNkHomlIG1pPXcGM43 z{$rcx#^S0*RM?`Ua^;W!ORQw}DFMu&+rwPMOM zbB|=S+@fv4)M+Xb!y}%X^d={!L|R(I-Z_bB+qZW9t#!m&o6%+J&6HGT#L8$&b_jK4 z{ECK{^rl^zb~ulZ}>wsh<&%nmvtrj@C$2pSe!mI~PXR>5-afsgGz4 z7!OUmFcxEF)>8Y%rtvxEk7>=OmBs3zrBuxMXWE#tWLkkaG8W7^V%nIgB@-7rKchBc z^*APyHm232+qdy0b z$BbDmS8+yXY)t;=b+XB2^!A*Q+k5sKn|(xQkR&GnBStyTx*#-MP{~Otd;Na##oD% z=6@Pv|9*vNu1w8!NEv!&MfNKqUQOpXFEU!1t4Sj>hvV2ai@8FI=Aoso{<}Je<>kLC ze={d6rv*i?sfr>cZ03_a@W|xMcpAMvi?e{*Q$W}LbCX>OqIxp5j!C@&}oPberZnRQH$@c+TB(jK8u zOJeRP=7po0_uQZjb^nk5LZLm9|KnS^d$}F4T*Tena79^Oe!;Z7vZ>*cNi71=8^WPb zRzcacqVmX1PoxVA$_lt`Jh?1ydPPBgVt7&+nI{?dhPj`Z7_KM@=S`m-F6A~UcS%bo zRB&&&X!>NVOyvHvk*p{z2uJU0=1rVfGOZMGBT!L@cJ3z^OfRQ^J4K45(=jN^59gJa zmrN|m!yY%AC(f8wFufwL!rX+NR8-9E=meuNk{~>~WKzW}YN!+IW#dU%L1|e@{)~wQ z5jFWm-03cwFr%U%;)AiUCqW`Nv?mtN$TyzMDyk?fnNfi=(~6o684Hnn=iH1f3C}1e zqb56v;b{etTt{w&mlr06TWlm6n>|a)!sP|rQb)Q7SDUl{H`6AMsHMy>*j#iGL$eA? zrv1~`Fa!B@fM{H}yfBYUO(5?*+&1glKi4cMW&(U6<5&o*g~)X!jw>?js4wH zw8iB|3oNgAF9m;7((GZ(mlln2nna$_SgaXbcqjd)LVCrsWNl~PEm~;h| z6`VEUywXxmvAhYzoB}1y`A748YcJgfm8mvqp^^n~^poE!-(}G{>D1!>4Ct zr;i+y9Y$hQ>WJ)d;gLhbsUyaPPt6#SmKYwAlQn9{=+WVkqrw@(vobS=5SB4waORk_ zj1j}agGe`GWOg_+V|Ye3O0!2sk~XW#7(%+C;o(C@4NgaM>Y$9wjO=lV;h`DXBaF_W zC`}D#rH;zZ7(6C3byPTO%&4r9qlcg)4YeaOMhqQ=l_A52kO>qG9+@?6RK~FM>_ie} z6POsz9+jFlWO(YRQxlDcBgyipa73gBUZNvBWUNU%Iz2TrGdw6Gdvx}wA*sWStSOyg zBSsE4Wi)0)T55L2$PwW|L&!?%piC2pZbIUhN*B12rXhuhN+M82b?r;l{Mru(3aWHgF)zxgu@=mpD7kIy+>Vmgyq zMGU59Xele1R?>j8uE1!ubVx#UyL)7&*!J?GR!EVrf|sif5G-RnVD)^JXwi zmKDuu9*VIL$<^O;V66Pz|FVMeQbwwxnFYnOdtj{0jAzDQdSk1&%m^ELec?px8Gk^AvenbY=!=-sVK=6dGtY$;*;-sk(z-=X%L zRW!AzXA#|DWslOr(w@zIvUz|(n?L*l|ANQ@O)7fS@;CG?`wA(G=Pev@#p4N#fLo6H zNh{X%Y|V;=ajYSG5bOW7VHLu*tg{y{?O2hoy>wueyCYbMEi6ZJo2RpMVP(0aSW+y3 zFP@I&nT|xh0yXOnnw9%{@$GeQ*2U|?8h**F1K5xC0sFI7-^r|~ni9F392~hxF*I^3 zBZGAVPo)5cbE#==a-7B`s=3iHhFcM4UDR>p(B?p~=?TCR`}BkNE9%!-9qvIcw=tL%NkvJ1DeivO>&gVh1=kOx>!qAbK?X39so@`>B^g`C$Giw)5p$eyR zF;z@O)-Y{9mnt;h-V$zRZ<6xm_+~9mIKZk!+J6klIhRVqI|-DNwD|0ZOSj)&xI@m5|%0LsVPVJdS5A)5BDIX_P-$ZS`<< z1ncUB)sd=`>a4n`uIeatv`S$0{bN-(`IFVr6IFNCH}A>H#K$S#C8&Dyg0w!Y!zQ`D)fn?78PU`_KZ)>j;* zM$2EaQ?|;NDw~ze$FkCSjvB}6uxG0Ayk^$C86cOH%qOUcthijjDu0tzp(+@fw(x2YO+ zySjrn7SyV{)ZOYHwOrlHyI$^RRp$rPgX$r*lC?4)QID!s>M`D)@Pw*UPpYTX(`vPP zMm?*ZQ)|@o>IJn{ty3?mm(O0eF?O9;eUHXX^3#EPb{@`MN+)(vx|CeUYA`r|M!o zO;6V)x>TR5%XGP}&@=Q*Jxf>W*?NvXj}>aq*B9su^*nu%zF1$P=j%)LW%_bmr5ETc z^g_KzU#YLsi}ezHwZ2B`9_SedXs)vzo*~V z_4)(-q5ep3)*tIn^rw1@{!D+aztCItm-;LHwQkVg=x_CRdYk@U|Db==+x1WSXZ?%b zp?}rC>ECsu{zLz%|I$14F1=efSz;+mTb5;8j^$dOqx7U)!FJ|b+wMNjo}_yugmRionZB`PPCG(zE(f$B&)wQz&e>Xm8Mv!)*x%Jm1YgGhFZg{ zbSuL;#X8l>w1!(FtdUlhb(%HG8f|4;W2~{(=~j+4&N{<7(;9D`Wu0xEW93?T)&y&! zm2VYTldQ>Bp;cr}v8GzZ)--FnRbrJ|=UQdFVYb4WVa>E=S(VmoYmRlEHP<@dy1=^7 znrB^PU2I)q&9^SKF0(GTs;mXp71ly)k#(hYm9^MfVqI-rV_j=4wXUuu{DYm@b^^`7;RNurIXd*%#Rt+n3n$?Mv;;?91&cdx3q0z0h7{Uuj=uFSeK1 zSKHUv*V;?%>+I|88|-TPM*AlFW_y`^i+!ton_XkyZr@?wY1i6!*>~Ib*vsvE?fdNe z?G^R|_Jj6A_DcI<`w{z5dlhdCeB6G*uCt%CpR%8}SKH6n&)Uz~YwYLk7won6I{QWY zCHrN2z5R;)s{NY1!G7I-!+z7=$eZ5Yw%@Tg+3(u#+3(x+_6PQd_DA++`(yhP`%`<1 z{h9r_{e`{N{?h)+{@QM^zp=lyzq7a5-`hXfKib>vpX{IQU+f+Bul8^D?{=g8hyADh zm%Y>8W$(6|9C4JR9m}yD$8jCc@twd4Ir}-Soc*2F&H+xGbD(pObFkCKImBt}9O}e7 z?VQ7$_D%=qaOVi8qZ4+HbUHbmoi0vS=P2iBC&4+!Io9dsBs$%l9!^gu$vMvH=X58>8Rwkgoau~r&T`In&T(>`JZFM4(aCoToJr1Pr_d>KrZ`ib zVrQB&-6?TOopYTsr`)M=gf7^cP?-)bmlo1ITt&ZIP;xLoy(ld zohoO6bA_|eS>#;lT;(iwmN-{C*ErWYOP%YS>zx~%YUf7hCg)~nnRAPCt8<%E&I8Va&O^>h=V9j&=TT>s^O*Cv^Mq69Jn1~;JngJ@ zo^hUao^#eX&pR(TYn^q@i_S~V%g%b|73WpwHD`nKy7PwfrnAv`%X!;*$Jyk(>%8Z@ z@6I?h$TBH|!qicH*4~kGh@RF1#J#30dcM zl~ufb>P7b`-j48sT<#t%_qz%5l6#DMtlP~^bi2Df+@3rM{hXWR9_RLQk9T{!C%Apw z6WwIDuiMW($?fkBa8Gszx+!j|JIEdErny7hq3$p@-OX@MaZhzK-Qn&Ccch!;p5~5n zN4weX7CN)>=wF3?i6>bTkKAA zr@JL?se7(l=9aq^?hJRPJIk$fXS;LU^W3@a`R)boh3-7}BKKnV5_i6PsVs6Yb1!$R z+y(9x?m~Bwd!>7oyVzagUhQ7vUh6J(uXC?=Z*Z&K8{M1So84vZE$*%EZElTwyL*Rw zr(5gZ<=*Yy<1Tmab?m?&IzgZk_w2`;_~%yV`xm zeb#->UE@CQzTmEP*SRmcFS#$f>)lt}SKZg#4esmi8}6I#M)xiEZTB5_ll!jwp8LLA z?|$HZ=zipGc0YDMaX)ppxSzS7yI;6l-7np*+^^jR_Z#v`=h(v{mK2= z{l(qk{_6hb{_Zxqf4G0Tf4Mu|UG8qT$rDd`+Os^{b9i;6=lNbB)n3Tk&ub;iz5Tt` z-T_{mcc6EWcQEfryHS4h+IWX}ZM{Ric)81K=N;y?mutKZ-r?R6UPmwNv1Yy3$?NQO z@w$3Pc}IH*-Z9>>UN+bdNdU{FTab7R)c(1qI@D%G_O9`+^_F_qdDnY4c-7vG-c8=k-ZJkN?^f?Nug1IGyTiNFtM%^k?)L8SmV5Vl z_j&hwE4&B12fc^9mEObNBi^IlD(^AxaqkJQ&U?~(%6r;d?LFf?>pkbK@t*fy@YZ_k zycfNfyqCT8-Yed#-fP|l?{)7D?@e!`_m=mz_l~#8d)IrV-uuD((cA9*R`TO~;{Qdpb{sDfRf1rPmf3V-iKg4hA zAL_^Z?fk?1_I?NdaQ_IuqaXH<^gH>T{Vsl2|0w@xKfyo7Ki2Q&C;Hv}9)3?h$v@8T zhDXZpka z5&lR&%RkK@<&XBW{W1Pn|8zgcALpOppXrbH&+^aq&+&8pJb!{e(a-k_{7L>~ztAu8 zr}$I-Vt<-H-7oP={d4^?zud3zXZSPyS$?HI+n?i~=g;-e_b>1-^ym2(`4{__`1Acs z{mcBz{VIQfe}%u$U*uouU*#|Mm-tuv*Z9}^Oa1Ho>-`)2YX3(6CjVxCnSYCatACqc z-*75`QLHGhNuy8nj%roYjD%YWN{$KT|? z>%Zr}@7Mbu_#euX{zv|1|6~6X|5Ja9|C#@}|AoKR|I+`;|JrZxzwy8Izw@{G-}^uK zKl@ZgA`V-OCG3_1m!gDyeW;Hco} zAR#y=I5y}OBnI7s9zo9_DL5|Z6&xS*4o(RA1SbZ`LEoTXa8l4e7!aHs3=C3&)L>9B zI7kbI1Ve*iL3)r8oD!TGWCp{75y8kHD>y9}6^stDgE7I_;PfCT7#ExooEeM{&I-;B z&IxjZykJ5wF~|=Jf=R*TpfD&3rUX-i;$T`ZJtzrEgL8wjpggDuW&|^XSwUqmJD3xk z7t9UL4=xBU4CVzF1s4aG1oMMSgUf=;gQ{Rba7C~%SQK0tToo)1mIPM^*96xFOM~lz z>w_DD>fpxUrr_paS#V2mYj9go6Wku$5!@Nn26qK_2loWagL{Mfg8PFN!2`jA!9&5y z;Njqr;L%`J@L2G8@I+7-JQ+L{JRPhKo(Y}}o(t9l&j&9AYlC&ci@{65%fb5KmEhIj zwO~W=dhkZ@X0S1MD|kD2C)gCc8@w01AJhjQ1Rn+;1)GD9gHM7_gDt^l!RNsj!Pel* z;H%*4pdt7s_%`@1*cN;r{1E&YY!7}4ehz*Kb_Bl$zXiVsjlmzmpTS?j&R|!tJ80sm zLKV^>D`bb9kQ?$sekcfqLi>eUh4v4%4jmAR3mq6bD0FbBP3VwN+t8t*_)xphVWIY+ z4xz(CM}#_t!l5HWokE>MT|!+$M}>|KC4`O%9UJNvN(^-m^$7J0C54U)^$Hyy>K!^E z)F*UeC^^(O)Gu^WsDEfc=;YAAP)aB@G$=GUlolEi8X6iFN)Kg(P6?eF$_xz;jR=hl zWra=)jS7tpWrxOu#)eK0<%GtC&Ip|u8Xr0RP;MwMG$AxGlpiVxO$tp86^4pJ zQ$kZi#i41T>7kNPY3STgS*Scz5tj#=Pli? zZgq9H7F#x6f`?5RlSE3_UFyE)876w~bzRx9V`pq@jLjI&le#5!-0D_(@sdG_2_!(` zY+x%JBmuIr6GCv19n2mG5Rwqc1|%#AS!M&0%y@=^^X~a}t26(>j6Wai)OoL}&b_y8 z{eHi5>UO>FDbJQKEMHVUSblH$;_~~-?=N3czO?*-@(0TwDqmK=!@~!3D%D0#ADBoGW ztNf|*r^}xyf42O&^5@H6D1Whhclk@@d&*xf-&_7l`DppR@>k3AxH_P8Df4lsh@^{M*l)qR0e)+-j56V9*|ET;>`N!pl%a4>FE&rtaSox>rpOqgk zKT&?N{8ahr^3Th^DF3qjO!?XJugbqJ|EB!g@^j_q%fBnXP=2xe(&XBS^;7cTabbC) zcY1hyb!B;CsCK+}Y<1z@h4EoF6TOv_@;vLFiJ{u5!STgadBS~SY2p5<;}^Eefz-T* z$K~PpdUYB3Yn)00Jda=rFsQHSn&+PtWC=k?Ftx%j-PXJ0t))blQEPv5YuA=CGK zopVx_Ff1?06Vt`x<2MeE%ld%vrEI2e+`iw^HfQ`s9iXLb#%`3}k1feR<2UK?%X<7x z+YXst-sX(oq{lDo051>EtjOAg6`3%mSw3kNmQPOHOy}jV>+)s1Sv$Xy&CJcGHkMBg zS2s>C$zzzAmF?d6E!u`vZNn|w!cMPlbH;DcHms_-RgYTBX6n`pLpQZ{VSDZtZ=Bb(yrsyu}%Hb(!>9NpfhnT_q< z#8EE&hT5syFSKy#zHQrgY}day* zti?L4#|CVTjo1#hi|t|i*a3D9+hCL0F7dm>?-I95+%9pu#O)HdOWZDTyTt7hw@chE zal6Frrs8IKv?uxh=wEF^k3RQ^-6M97*gazRh}|Q0kJvq8_lVsic8}P-rZ}2oZd{1j zr@wt-_leyncAwaNV)u#NCw8CMePZ{C-6wXR*nRrlXS@fD_kj2V;tz;F;J5+D4LEL& zh~E&uA%5e=kLcZb zG8?_34bd8+HAHKO))1{BT0^vkXo+ZvUL|^!=vCtUsXNhY@|`v@Tu^kmd2MMZ&#*^O zJGF9QJGV>zFd3`8u(R3=JFBB;XEmOk)p&MR;ujs`dy;AnuO0geVZ8sKSwrvaY8p1_{Kp7VIl6F4q#T%h5B;{(SBjt>l6VBiAn z4zxSa?m)W(@xo?2+8t zAxsNlS_soZm=>b65T%7EEktP{N()h1h|&(Yjsvdafa?ZfS_slYkQRcp5Tu0=Ere(x zI18~^h|NN5wqbrX%&&&|)iA#r<`-0Fp*jnd+2kf=A@jYXg_Fl7GaZe#GM2enJDDZx zwof#QgLoXo;~*Y4+nG5fudc|8YquSxbJ;;Z4*GG>kAr?3^y8o(2mLtc$3Z_1`f<>Y zgMM74eRY*y16S!aaFC9JbR4APARPzkI7r7qIu6ot)=mq^=jH7eIt3Fsn8?9I4kmIi zk%NgGOypo92NOA%$iYMoCUP*5gNYnWQ4I>W%sX(RpeM> z{e|^mabze7xXxlhKH`ntDPI|hSKM|=w#G&QiyLG?@KBQ8)5qqAJD;<$^QMiR-?=EM zXKumH=PsICPOTKTE}lF+G`9^mCTNX$?x{sHkpG{%wm3aH&t^;Zu*0Tb4z~tidSP2n zc1Z)Y+oOKut^FJN{pO+h!y+F)c1(6JPL4WN%r7jh4<|U+*bC$fGx}224oa6sCoAsB zU0TXr(lO`{b}n!1ynk_GMf+t|Ppyp00`b$ss>sHyOW%lZ&PczG%m31xLKYjI98Ql; zyV7~ zB_(W^6!=|I!gfgs%Oxc&kH+`28sDSwJsRJm@jX!Mfm#pLdNjUA<9jr|2V^}U>j7C0 z$a+B51F{~F^?cLkJzIyQ0gRdTZ_28=q zUp@Hh!B-EydhpeQuO58$2z`&x_n!WPyB@*s5&YgOzI(6p&wC{~?{)rpuk+7)oqwJL z!IL0(uk+7)<{t@zCt>g;44#C+lQ4J^22aA^Nfrk05wspb>k+gbLF*B;9zp97s2+jp5vU%4>JgwG z0qPN;9s%kRpdJD05uhFc>JgwG0qUv1c!Z@#IC_Mmr^4c?u=s&WEkEFTBP{)Z>x;1T zR9-y7(jzQA!qS7Sp2~}-^5PMi9--;MR}a2=@YRE_9(?uSs|Q~_`0Bw|559T?sz;!D z1gb}%dIYLRpn3$VN1%FYF`inCrxxR>#drj)rxxSEa}S<-@Z5vv9z6Hpxd+cZc<#Y- z51t3`F@TQ&d<)=P0N;Y*TQ#TnEjHhmV)K1j%_)wG&G)a^d_BcxUJ#q_3$gjWtmYKA z#PYr3RyC)1B{uVg*o+rqGhT|#^F?e<0K^hc@k)H!rFbQN#tX4|K8ekIC6@LmPE~V? zQ(}p$I3+%D6{o}}uHuyV^iy$4e8xj@N_^rfPKi%{6{o~!JQSy@ImIcl^jmRCeEO|8 zB|iODoD!dYD^7_|zZIvdImIEd^hXO7;?o~35L9zoAP`HtHIc986i>u5ewrYQ&p2v= zT+L~MES7Op{1KnHia+8LR}*CM8AnZ!#b+E9pTwsGmeT+)tus!SjJKD zNqojp6J+rjM@^8$C$8d{_{7x&S$yJZf-JtqZB*w}jp`h+8n;oMBfiFMROg7VaU0b+ z;_LNmxStx;Ir6#2Z&c@qukjnzIpPyv@8hb``&caTRp*G$`Ble=uk)kP`&@jzt_}BV z!~NQDzc#94sz!B;SkA9HMtu6GI!1i@r#eP_;;W7kpZKa{#3w#@(0~ICIM9Ft4LHz% z0}VLPfCCLU(0~ICIM9Ft4LHz%1C8pIssRrg@Sp(?8t|Y24;t{G0S_ARpaBmW@Sp(? z8t|Y24;t{G0S_ARpyB>*xW60j?}q!k;r?#8zZ>rFhWoow9a1%_L&WNR*{BYw8ZBIk z)%&sm4;t{G(ZZyBuk*jr!ld}jKP^m(&-~NEr1;D~ElgI87AD0qKUC+4&-~DQT72dQ zxYK|;jTR>5d**`{BE_daF^%7zD>>u$skuE@bH?w>X7cvU^lkFK&8<=1QZ-tL6stJX zXdzO3`m2RV@#(J?BE_e_T8I>%{;F=P8r5xL>96WG@#(MXHu34N>NfGYA5^!APh4=c z0Y@8fv;p@TaIXR98gQ-w#~N^~(L!IL&3SFV#s^qdG|}LT%JkLn`vx&Eqysz!B?*lPR^ zod^$PqgPv1kbJ8w)2QkZUt6C*>jYXS&^m$E3A9e2bpovuXq`ao1X?H1I)T;+v`(OP z0<9Bhoj~gZS|`vtfz}B%l{71@66l>k?*w`$&^v+N3G_~&bpovuXq`ao1X?H1I)T;+ zv`(OP0<9Bhoj~gZS|`vtq27{aomB$86X=~l?*w`$&^v+N3G_~&cLKc==$%0C1bQdX zJAvK_^iH660=*OHoj~sddMD63f!+zUPM~!HtrKXSKu;Poj~mbS|`vtfz}DMPM~!{y(QFJ(#K3y(#K3<^=?X_c>>K7Xr4gx1ezz% zJb~s3G*6&;0?iX>oinkUdaf#wM`PoR0y>S>iwl?ilDpnKBCN>$RwN@5i)l0H@v zU(q6=MiXeBK=TBeC(t~B<_R=Upm_q#6KI}5^8}hF&^&?W2{ccjc>>K7Xr4gx1ezz% zJZTnQB~U$~niHxyp_&tDpFsNr+9y9z2J=66}>=uLOG~UB4mwD|;ucB2-DM2x5t=RRr;s9g|iK#OHp3 z{Sxe#V7~vV` z$plL#tqxR4s{>*gPpt}wuWBg4k7<)1waP2sE4wGH@`_I!t@6qOj{G=MY*v+G^Eisl z*`C-OPi*F4v3Xp@=D1>W|HS6&C^oacomGAmTa_mkPj1NDU}P1^h}z|&Fq2q%&a(vqwzsm4z)E{~S|t;v(XW%gDwl5c6Gl9Bjv za^e2t@_a#}=y{cH-Ql3o;oN@*t^m=3SvK(-%*;rj+55`m> zQ}*N5Xm;?}5CD$1H99lJ`UqODW{iq&gUX<Y>BQ=_s%(F9VQpO&*viYbc8$jA)Z*&=fU zidel6m1dvf6EyTDA?K*v9$&5AJeE({*|3{qE^bk;&YLh zOcj%eN(?n@meBvuDi%)!|W$}}a zr2y?{X6TF%XXDIF9%I?e^J8nT(G=NoMzci6LyP`as+#z;OX*uar(H_l;?pioUd5+f zO5@@)E=uE8s$_azrE&3@BTD1qGcHQw;uBwKTzujyjf+owrE&3zuQV<`@ip1Ck_T#h zrFHR%ue2^c@s-}iC%)3V_{3Lw7oYe_@8T05dKbQ*6qFn>>rfd`=yz)2ep&P&f1a?o z^_kzbaQe*p1A?l%BnOwe%kuh!tbiE3y|2{85Tni9bivPEYa7P}HstRYMhMIzO|cr= zY6@%xYo>=1XLWJy9>FZVz*h5M`BFO~GgnVi4W{MAM`u>#tw<}&!=+L-PK{QK50?u0 zA)BRza%ttHybW!%^na4gmDTA*d9k6026;Wv%5ou%k-y!@P15YvT01v6dR5Wr2UPU_ zwnzkvM6jB#TC4f0SlXres`&khHF>w-(r{JJjDWD3ms+cNsaU;`*854(B_~%mw#Ex- zVUZRVNntfZl_MDe%}~W>81?yr_&SBGW~|m~#wu2CZL1lp_G@fF6bX0PINPR&xq zr%%Wzi;S|GrCO_5s#yAjtg^@|i>$K9DvPYL$SRAhvdAintg^@|i>$K9Dp?GfXP?Za z4Pk=y-J_{Eaz_6wtWU}qnLY9_YxQ`(Y3lUfV*#gKGK(+uf%LC+dYoz3RX@M+)V@I|t4=aL$2q4qS8KnFG%pc;>(_*7pg3Gg{!61HT;j<-jdR zs^+v3CxFjY(8`NbwvgoC8rDh~hvLM+)Y+{~h`=@O#q3bb4#n({j7}>#LZEKftx`@O{g-c_Fk6j2$e-|m zUb(>C8%VeUwTM71B5)T6?&82*9A^7+La9hxh@e9rxQ)YX8tow1vDpNz>I>B>$A)Uu z##yOuZ0(>IIgrzZDvoxLwQ^fK=qzP5hMXz4p|foV+MthVWd{YYpoM>7cU6i(3;*Kh zCUh^Hfcrj>CI;^Npp}0)fEJKG2Af+@Z#w}k(9*vgKnt|=FS>#jXz5@4+=6)F1Zb&% zmI`R80I~#-C7`8(%Pk1oPCyH&#sn??i;`g`05t)q35cu!)C8(G0f`lWo&fX&peG=; z0uU5{pa28~q*m~wc_0h!jJsmriW|o~cP8 zEQnrPUDxlI*5&Wv<`;_m@5KB)YDalTpd1#!;y|e*Q0fSjIs%$4Q0fR^b^x;jm>t0E z&`p!_{`4iOmag1Cew|FZ&A|q=1E3uM?Eq*8Ksx~10niS;?)Y_8M{cNW!l+0)I{m7o zQaZYzb^x^lb&f!tBS@V?UeG=~xp7AKr_K>5ngxnxfdWUMz!4~L1SxRj<5!6%1&-`f zBnlKb0tJphfg@1h2oyL11&$yEj(q&m32hGrj(|=L6gUC}jxgwstEgsoCHsJ!4TB~R zj6Us@ln6l5rw!u63;MJ{eAPaI@pqK+Cj6ew^pqK-SIW(b^({1gaPTaUG~) z1gaQ;Dn_7+5vXDWsu+PPMxcrjsA2@F7=bEApo$TwVg#xffhtDOrRXD!%>Ai(SW#1f zt&#UN0-;7A)Chzcflwn5Y6L=!K&bVhznouZK}{v2MjzBva%&!H)X0Mxc~B$pYklZ% zYXp9cI;g4m))YT#1bmmR-UcskE8`Nln8f{Rc4QjMO%~O(^%5jY}sF4OW z(x65f)JTIGX;70Q)RawXT@+wzltGO$s3G>+btl)PCX#;=Kx#1eZaHRcLn|;fSwjuA z*Dj5pkhfecX#t`3)z~&i^<53E*U)+mt=G_c4XxMEdJV1D(0UE6*U)+mt=CjgYBG(Q z3QA4JQIm1hWE?dWl$r`kO$Jg^L8-|=YBG?T45TIlsi~mUWFmD)#o8HR44u5XB0x$e zc1(W7;us(L;?#n?U4LSJaVXC~=J`}pxtbKEuDesGH`YdFuu)NN_qOfL2V6B-OAUM1 zuy+l6*RXdDd)Kgc4WZPqcMW^juy+l6*RXdDd)Kgc4SUzHcMW^juy;+xr6$X%VecCD zuE}z09%R)#$f{xQng>}mSx`+DRKwpjSx`+qrRITE%>%2N2UaxxA`lgUs0cJgpeX`P5on4)Q3Q%2P!xfp2oy!2 zC;~+hD2hN)1d1Y16oH}$6h)vY0!0xhia=2WiXu=HfuaZ$MW84GMG+{9Kv4vWB2W~8 zq6h>Hq~1d}3|6v3njCPgqQf=Lk+id1qV)saYbBvKuTRCXhk-3Sy#swGj^B}rjct40z0 ziQrEJe2ZE6Yf{_P;kq3eiy&TcY5&av{zY+Bqk$@2i*hTtvkz!q>SdaUy53cmVl|H!A z2Uq&wN*`S5gDZV-r4OzQm{$Yl#ejJ+U|tNE7Xz;Q0NxqEI|KM;0N)JYnE^aAfM*8E zGd=KBY|it<=7;EF^E?%srJmS)pNq{EU9q_c(gR<`<|2sLtoX%dts*unez7^r6q}!b zh~@l>pW<_V#ZU1$zv5*NycEm%6fec+e2SO7sC*}uekk9GPd{|whWPYDd9W9i2W7cn zZf9bBkl1`4vAMls^LfP1jc>@)*Ep-DQe)LPHC|0nQ>%$;I%>LVdTRP=25N}VsF$+o zXuOWb>u9`=#_MRjj>hX~ypG1}XuOWb>u9`=#_MRjj>hX~ypG1}YP_z->uS8N#_MXl zuEy(XyspOUYP_z->uS8N#_MXluEy(XyspOUX}q4s>uJ1Rju%so5L1p2Q;rZ*ju2Ch z5L1p2Q;rbz8pV_&M0vzJzjUL%%WHCOaj1XPUi3z9>?v*=y_~H$GJ0`BIoNt#T`?HF zi*DwGyml=A)Y#|^KhsjckmXg?q2t4~1$AcY?M~e8^tU@n9a)C5{QQm45|x!@PT=!5 zyYg}`dBK>j`;v`A_btvZ?B4wN(3<1|OXhhi>-$9hYWokZJ#hNi%F>#wBp4oBJbt%4 ze3In?dDF`F+NR^OGitj?-9sl9mxnpD=(0odV|MFXj{KO{qB?c@`rSsy?B>+@YBK4iZ7;MiCG@u|gE?l50DJob-IHUIGU&n*7o zN%Qy5H2Znm=#Nr$2RR@#)rl z>QeK`bLJBtzqI&7Yd-#psp8|8nm;>h{`6Y&F>yY2t@)GIeDot_@zK_Nq%P)6H9yxL{wMRZt@)YO{Pe}%-i>wx4rdX@wT((tq09dw&o{V^W&{~%bTw#-ZF3A{HDFd zo3Ai$+G~ESG(Xy!H%gEm$v35`^@*Z=KEUn;(h(%#kZR8ZOw!Cn-{(CZ1JMj zyzs0!d$swV*8Jz)<^`>}uQm6!W@CN2*w|w>9^G-#;ZKgOPn-28#?~%2Ylp{HTl4(Z zoN3L<@~y?nIkSBFnqv7@bNU*y)S7#&d0uN4tvU6iIeFfkXw5=v=38_8*ww}H)*QQN zZ*lBuGi=R&YR%oP`R+TXitpZS?wU9M@dM_&#QCoM=FTZ2Gx|ICo7-FSA6j$tsw;}4 z*4);bTU&EWYySON^W4_lyx-i^n&<2|SUjgSH=Z{)Tw|Vn{pH28qq%-?adG|S=DOzc z;=0xx5%0*nN#dpRrn%hA$p>@M4EpzM`(3i% zTr9_5+?svT^L>4@S0e1)XZGsY?b$tD?Ac@X=-BO^DU03HX19*rjEvn(X=Y^X-ZM5m zX{JYWD~?UIrj(wPt(m;c?AmK4S~D)E9&b&t-x%qf{MyJ)`C#X@W`{Ij$3b(^UL(JZ XH2;!U?0EYBKmT3y|9Drv@uGhLW8jS} literal 0 HcmV?d00001 diff --git a/files/mygui/VeraMono.ttf b/files/mygui/VeraMono.ttf deleted file mode 100644 index 139f0b4311ad2e0369a347b3be6c46e6c2b730d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49224 zcmdqJdq7oH_Bg)x+2@@5e)71yxquf?c_Sig-y`84XoT{ zYwfkyK7lJhfpq z{r4HT|93*_U#lpsTJ>sT!a{(5oDi?c6=fx*?``~J1hh9p`_UC}L7&F1!F_;FhE-J6 zuhPEx02MvZiBa9)I@S>%O_S@`pz$E92_ux(K>zic zCtSyr#A$t8#~jgW>s`le$aQ|mu|RyZ_qf`KWVCj&>sUn=>ddZVH3{(B;X2llxParX zV}mtZ+cL3c#p>G1B^CAd$i>6$32||W_C>4h8I|>Q^|fUsRZ;ew>cuhk^ySO#h1jaj zURYLFR(oezY0N+y`^>W168rR$>N@+hn(CT?>v$Qj;>GB~nyQlO!m{OMC3R)?_?Y;( z|5e8Z?XUH0&<^yW^j%qJFR|CxmXwxNmDDb?*OdR90E5<`Ehww4s;sN4tf{s``--yK zG9YwGZAo=~S!tBLytb?iA6#5fQoE!q%3fb%FR5N_Ur|)@#31Q70?_T)K>uX<&}%es)5kR&}?iGIvjwN+Dq!{Y8F?PK!5hq zn#B!OW!3d1^@vY-sPNRD=&eLV%%umdcUe8ydKmK4ghRPX{k)T%xCO;MM*7S z-LSl*Rwlo+tgdni3@uS7v5C)YJ<7L~zxLbwee2bA5NHI;IA_+;6tdKfqMk`*gpkd-W24uhaZmWRxk zTNz(pQBrTOD5(SPmsJn&Uj_-?4eEHQy`j3)h4LV>vTX^K{mcI#*}9tLIJ#xgp`c3a zAiX63u+BA(;m+b^B}>ZeFlvEavch7+|GjFtMJsm&h6@aI+46FQcayX1+4*@z_UZZA zMYGZiv+Oz3?FEJTGjlStGVP)1)8RZc%04TnXmb9HB0IDwOwTKtZO_lPr{~SKPtD28 zjIw7H7ZheqpKi}DwC7AK$j!-uYdLunb7y4cB6g*S}7o+S&h3T1D)6xs4Mj?jzMU%4%?Q)YC zz!G5Cvu5JM(^n$F3Id}kk%qh&82-reP z;5~2xt^%Zq`FYc`ZkquYpq;x55Xj^#nGPTz9sW<0F_X#919A~gQGOvX#D&VNoatFn z_VmJ>=_rxx!hAp%Kv0srU$&L? zD{Ix_vK27m>fD1|F_N-DRjepDDHxfGF#xTeR1L#dxh5aN@PzRtyE?_n4cG%Yx&VtW z8(}mfU?#yUDMq;T&N8rsb!hp)YSf@nSy>5A6&akb?0?MskT;P>hQ>XMj>`uY`PV`EpYTp6>- z9e~AvDI^m~4Os#4VlAm8OCT<-Cw3A^7L(!dn*h;f97%+uMbN@dGN4U8se?}~DI+Bi zp+>>g98wMKW8f&AEQdckM5}ICb@EvmJW~eG+zH>M(DIjX>}00gq6FGc2gud%gq=(S z+^XU8%l7Wp?zZlh(a?7d;Drzh0pfD_l*ql?Nj&r%5A^(hN3nru|JO8Q+h5W#l_Q4(b?i7t_Q zs)im>G6<_&zFRiX<6?NC1gSZjjFO)B86hd4qx2pn}D81DK5U{nvo8|Dk7ED9Ijx5i08}K3gio zL)vSgeI>wC=(EEeywU)CMJR}CJ={ku5SvO_Ul5x}xQ?8%59t9l6Qxj3R>E`0L+o*o zCwOHAT(5y%8e}{bJ|Q-x09zS1mB6D0fPt{xeYk1(We*4)Ik^}xYmlKRTwMuQ@#z{F zmL2X^0!?^rC`E4ggJT?rGv-FmqA&t0O*Tk*mcks-v2c^@VdhFSiq+i z&QLmvB~V~j!a4S==&&2B|4y}AjtaJlo+%XGs&#`Dt(5su1^xWbJ-A0hIZ#*&{6*=Y zyirz4kEkg~NsUZ*oy>`)&|)#%ceio(gL;hg)_`WX^&TllO+=X}8de7x0QU$jl6ynG zErNDv7YF4qC@nW%vA|;Cb4VeMZ$(;*WITrIo5B&i zg7AM^rbsK&pvb>U{#DM=YPtFJ+Y-k%t7U6a4*e(;#r%R>|Lu9S`Dl?88W02IJ&tL& zWkdXN+~GJ?Y@LEFT3WQVZrKm&voiKj-*CJuylwy}cs58CK8sd%3GiT0%a=eqq^QDm z4WDq^QlwD91ludz{W*{D&VQ$AP~r*&gPMkv+5w;cEe5yt^K*U-QtIY^ojfK`=GX&L zFjUGo8V0R8a@#KRyc+n1_QlO-JG4@+Agzj4Dx*NL%*Yq~pcg5FBZWglIlofYvr?JE zp}*oAL*Yq9#%}JqpFq3rjv+!JE*Ls46 zJ&Z*VLwsVWKUPNSVu+VYKx?pf#n&p@HE3bo5dZ(MT0bAPgH$OoH0rV9AIopiyU8R= z=2kw*BSmmDo#X@WipVU8Fbm~-IdIJmv0WkDnF&#MCS1*gE1}Q=@8JDVd1TIl<03K{ z+Rcz*DKHA59m1XsZ4oxc>v{6oRA`?Eu+Z{lkz%=zEP#ek^PxY4Jq@nr!Y}rT?eK|- zaAgLZCan6uB@hg6o65-ij4MR{BHCromYuz@O~GIUQi<$nX$< z>_1zEnf8A;3+)At25xY0NPE5rxZMpe~4`!w9Nw;h4Swt zxQ`epl2CXx5n2^M-`HXj;8i4JfjuF0*b=cSg8S*f5qutdohn~dc!)efDI+d}P;lOa zeJgk%|7W`3p$;JZx$uX)MLtfKd&q*T)8Lu{SAl8=tdJ7KTj9nGIM0NZ$OohlVcWT)Tdr{V zxH^EMM8NL(pyKxjV;#j04UI*SBW|BL=uzCZdJ=dU#rqCzH+U5}i?bp0UxRZXZ0q*V zznnWGrAqDs+YOC`-O-2=O)7IG^p6Vu7$ITIuEc~G`zcY15^G>ouFSG=HlWN@-Ln{+ z9inf(b^cceIAR=tSSWqD{r?~=oO@v|10x6Q4LPh}gS{!-{BOSY=QBo}sp7n(7T~Ou zkLzWus^Po@ut2DIx02ii=k7U-k{>`C24(d>$-qs^|HOZc6zf2PlsQ(V%wdc#W1ugj z3^7&aYi|B394MFXVJzXs68Si&eHd$xm7g6Nmtx$65xb&ON@f7BVLwZtPt1hX12$tx zEc~sM|6(AXQ2h5`1}w%E6%x`(&dZ;6`T+cv!`f>n+03mY+`wNaISp+%xm_ncPq)&e zaJ--N!S@F8E!DDDX)+vj!L!AD2wZI@d*r8^+2^Ez9Vc&*v*ZIf`kbaPc$U6JLg+`( z&(?uHIMxMcr{Q}I>te+;m{yS|=(7NE4e6vcWE}^;Tp>VygTDw@-yoaeZzp*ID1Sr7 zYy;qbnH(Y8$Tji^_a&JF$4AK-z(*oRr61Zut^=fYZah~G?alzS-DEf2Kzc|WPpB4J zek}BGBLV6Wpnw41_6R+~BghZ=FrWf?x1S!T@mwBx3!Yy?ir74M z2m63-`T(j5w?&lB^QJq(UUZ*!br1NPFM2_<-aumZ4I}QUr5`@mjH7S`vJ~F z0JA+Z#e^K;3WYo&4`?ojYkTDHX60KnlQ-B6;QIrdL?`pvEDh*c!{?Gm$UcA@0h}SE zh9yDoHDryjUHK#J@E0v?XDz@{nHw~b8&CFd<#ZchdmXr0!!k)S^bsgrB^&7xz?-Pn zk~*P>5KrsDZ47YkJ~m|G= zv3IxYgm=BzJ8Rk7V_6TJ^o(VfB=*){wZdBx`>U2+l-OS+cHusYa3O%b>CN7d*y}Cq z{5FShUSj7Yc6Kd$O=7P~>=lWf*=-QIC3ae3rzG~W#7+Xdlb-B^o^}2Cn9wD$KOdhj z{P`IBb0dHJm_s-|pB;Dd#~kda#9nG)oz3aOixTUApN<>s1%P!#V$YYd!=>y`Ms~=` zo|D+KlCz&ZBe8=Ld)ms{CHB+-qwrJ$J78o_?zad}MzZ}D_Qxlpg+H!kPeijnNNk_P z9+z0#USFZDlUJ;OKj6di?B&z8!ha265AlLdo3Blz0=uxi8Zcb>+V@AtdrP1 zYuVZ$cDKaV7};GCTPd+SCDu@{7aB~gp_3Bl`+U8g)t}_+tgOz-*GlXTiLH=WP4#r4 zriE2kMGDo^Syd!kF0o|^Y^lU56IjI!w&WNqmspv^N+q^U5U!6C^esP#AxMrAlmEBpWNS6ku>lDH{{-CybfOk|j1e+EW-Uv81VNRGgnM zYAQ>FpG1izK*I!y#l!7*KNjc5V&N#(hs9{Tg_vV3I?6+c_GHnW9CjOJwg^!kEDF(W z;YW^e2qPsn0$Pr6u;JWTVYtL1B^DvEa1(QQX9$igHq6ArBo=Bi384}Tu}2FbYneTo z1y5x`&~uQ)0wopzybX|;KS;&jm-$J|S7JUAvjGHKHuLt17Q8c<^klXQy_v%6^Cx95Sr7ciy~NP|W)avkwUY zhnPcsh|mVH|(n z>v6C1=Y^jBJETWxS%0TQI9kZs8AMYuR)Jt>=vE$J5uOuyUJb~6h&WvXh;h^sCjYT@ z&t7~MfIwu1AE1nbD#$m4E~qdJCR3bo0X9_=BfbI+^3pVUm~<9Ha8O`?zn_oI+rw%x zn~Vm%R-;yA<0pFB&6i%cA-buTQd9d<@w+>rHvu|ii5`h8(JMs$gn5LqFprR=5cxyH zSR!|@;=9VW%4^c+MK`36D%vWqSMIHlBs#oEx=v#&sQSC2>)>=t=w7L0w{&=yw21y5 zKf7q&Zo0SsRp~HL-6g%n&w-dqgzRlBDRri(BZm>ya39{`8EdwAP{+1mJAxydgFLr+ z?4ZrYkRUTJ4pT=7L?`-t2$6Oph%?A$VyZavC0lB*Euk;9*W7pID$w&vLig3{SIt*n zxqj7RO|hg{tTyc^TvZ~J=9SEZ{dNFGY^D$p$f#l->tbROj&9!4Ax#eBt;73lmHE?_FP}DT+2+p8&W7md_@kRP zcha=HrOT#GTfQ`Z^Gk6tvGr*ikG@F#7SeqSKh3X%8_SmF!HwwXhV)G@b;3|0DK|gi z&%kVA1jO0TI~Q5ZoYiF08}vq-!JvUYHi3E|_g=Yj{p#Cq0{0YsvDi}Lz@n(k#;@UU;79mcWft(t>`+Qkp&}v@ zQCn*>3sbrl4Q6!HZoy>*Nwuo>>pO`YWy(e$_(WUQ7pWU}D zA@0>@(l=y}Tbos~V(jR7b6)c>F)bpH^jOQp4+8zbc)4 z-=vmjeQYmAIOa|pxBf!TALg~b>SHt641{uK*3Naw*2VfFC0lr~D?At#G%4M(LE*Yw zrUYu7X}k0-YY?q462Yp8d&r|kgNiV#2qnZucq*Y6_ymulRTDWcPpd5~oJ$&IO=b-n zH*DD0*80#xt)lgcH14xcrLmt~rKkV?5$)~;xbpyRgd463;i{-kO?-H(4&e6nCJe$& z^tO6=a;mV=)}&D!ohQR=1L&f)S4#cpV=1-w3;N0@SLiEPlf9pt!jA;Kv5-7xl-Zyo z5JjkfLN$9#u;?GtQe%r%t=BS*XknCb#Mi{@G`mvS=K-@~atFVf-wES7!s$sK*U&cMaTU{Zemn_K`)NfzVgQy3dR7iV7$IIE&?OjH z3wNCUS(ewI1K9TV>kcjBDUU!Km(F^P} zz20|b_hK4*L0V7Op=?X(N34q502bHMLE1Q;5>SM0>>s2FUDHxd)BioU;R$H_B@D_> zX*{$wcaVJ?bf73rtnALh=$CzcG+w#@be7-D;FD$j0(>}7Fd9U-AcoBcv@8*P#pAFBZ7Mi}k6AT=Gakua)t`msN1tgS)%R-cxjUBkSB{KXLBA8HB;2_6Qj25`(^ z%*|J>!SAK3an83PlS5;b;u1+P%8x$aC~L?m6}x z|D5og_?+rF^>do%w9n~IkQ4L-cY>YZPY5T(6RH#H6Pgp+6T0l*LdMkAU|cy)Q#J>ZQH(M z+qND5`tG}b{p;E_?rL&DLGqZqTyBr_7wN2YPWlUtqoZjujcb!uN$aJ1rB!qby@#%& zTR?Kx!SiH;B(Aou2tBgBCQ&Am>9%BE;y1VweVsT~rie}c9Fgw%%JtvJOU^rcFENL|O zF&=HMDAES**}jHj)F-JlduQX^*H$cfwd4b;n_W7lr@g)X42_v^S8M*-9T^i}k5BmW z&kIl1r+Z*5qEh#HQd{SFi+p0aB~m~ z4ffOo4+ne!;Y+<>{6RB&K{Zi1G1LIlfo_!tw~8T!%jJe84f@^zq?vl>9_gRoEqQxM z`74X|A3prZ?%mt=Jg{kYSHd=)ra5wXZWzQNuye}-@9x7T~&2!A|sF5 z?H|0b1`=-^P}o208> z^-AB^?QbN+AKKS;*x>+fxGjti83x#ese*l5wZW}s?bAFY^>*;B-Yw=`j?f?yZU|M0 z0n{Vdfrh5<3Yud@n4g;E&>)V=j+>JaM8_0nhha%V61=JG%@wh-kJ5HbJNZgnd-c0t zU%M>zeM`fr=ah$}%j+L{X#J)wTZAJ=9TCz;(&weir0@UpEd<96^Z|Mo-5%V({OA); z9R1TX&mIDfZUbqeEfqmDRHLS}~o zC!ynzZR}wGS8s9Z{v@Gi=8g5jNZ6u9Hh{G9WSbiXQT9Zq!$(hABgEFA=vFIO-H4~+ zeDuRc1bGb$GHHUm{6krgDI_=!gw`ud4I@dnsv~DoK+lITz~PQ_a4fp?e;C9+9z&u^ zu441fhc|B7`LJ|u{R7|r<>I#wtZ&&XNms5&H}_6!TzyyLx;3jCxihWz-M6c?Y3n0J zAxG97zIgHQx+5VWukAf|<&(2*XX&C<_uRAUuEzDK`|E(BY?-2AWSle9LnN)f+#nCjFLVRi<17&-zfjBbXodm&O=;_Ta5i%LDV#a`j#%E+H3!& z8tFc%M%paZ1q05CU*#h}9xCGRG;sUKL4Kbo&_JHRR1ZcZnm-UL%o)QV=#U+4UmqVK zU6fM5-2w#J{{sY^c{-dPYViLU1RT^do&-`A%ncx(fqBgaiig z-AYsdIa63Vz*uEF#40O6??RkbfrkmZz@8PKQBjUW@)4+T2`Kw(y$~2_I4_z+`PF^T zvcjJ};zJ$#dIORn(cE@sOQ^6u8pV#su0)>1j>yD54_+VTJ7F4r#%DX~BzhJYWL5 z1$i^*M-Ws~tZ`=OV8*Kw^rFMp&zJEWCpi54d@}<51dbPdO(fX7&9q(L>d_LsDMYmU zdTRtq{OlS`zYq5|Q9BC`Lw|S)gAs63%758iUA-<{yJ~&|#)o^Fz$?=P`3H<@7)}I! z=CtH#B~AsrU}_!49qbxkG-pEWhN`^7ix!-yIC^>Fg5s?3Gw09K2X-&oS~z=Las2G+ ztjyynV@^JvyJ6nUjH2fF zvi0kiEo*GL-?5?a@weW3ykOI?Ll0b+F4HO0I(m6ZT-utk(xcLRx{9V=yupR6fArDy z_dfcl^hHft=C{X>f15o%ZBG}(GcQRmN_TmBZT9t{f2B=y6Ma*<{&(Ps10;V?_KI5a zh%=oyAk+o5b_l!*KB7Yqc#VT;)$pMXEz=SQEJ`sgcuiF+Jp@iu096s?%#}un)#`vp zN_qqal-p&h<;kB4=77pH(0!x^JA7EhD4p;0(-IS`Ks6H{)^j+X>3NMxRBxhNIrV%p zpRy2&fpG{6<0^V!=JluV=-G?a{ogIWD1`O%?AaS5=|%|_#2BnB68;XLM-B5FJNh$U z(yG<8TDQNHw5|w6P6+hM5eis4iz^a=jFe*d z9N^3b%yvi!z2jepT7G}vU;lh?!}^D$DfH;4KWx~r^GWHt^rMu`o$bH8X8VI%xpHa3 zinVu??tkTlt-ts5zR-3a=K|ZnBFDps^CdA(Ki}ucVeeLEcwT?l+^T6|yZk&7^dw%4 z^F!1I9W6vnaS$82^}{t&R$|}L$$b2@eRHLcrPDNx2F~3#ZA$yhGu_>1il53!8a|x1 z&=s_r?ixP)!gwcyyl+TvN`GMqA9`Az>B|MOQ;C^vKO~XK#{)rF16El#Wa7(#8Eh(aCh`Pd}{`Vx@sP0-;2`ERt@Ram6aa7_fmDQJ-OV z_7`zG`fIrpeJe4t$!_oeM2@IoF2)xFWDObS^l(Au{{$vg20KctfK?m^n0q;#!jLNL zOIFiAk1Okc6cUc@(&YC3WWci=WK;k$3M8q{5MMvy&HP#eZjn=vzi*J9jP^(nlOSjV z>(GajL?tScE-8t${~|F$={SxT+5f_9Ct-k%Fc}Xy%f?Hu(v-f_G(~z9c=^-1_I4g(5K5|Ue!`9eR11l6 z+VmeGsGI-=@OhTm-e;9Q`wF(;D_l7%rc`QyV~iZpikQz8 z=^%^DCl#ZGDGfPJL_;N;CpC}eDOV+U3pRDQ5Uw80WpgvQS?XdnmvffVm8eYXVE3JLPTfd5dwDK0$*XtlAs?gCRmevWTf1h97oNZl97NM zg~yO%wsrIFU7I)W+P(R$@B90&f8Pg5r7vj?^^-mWf88m4Mty0HbeGf!nTRcPGi{U_ zp?9>O4Zs;S@gO6eKD5;gsfaCBvsMj@Ekc4}jD-Yg5H8>T;ylo;@5;Km>m zz=y%yl{SCX^w^&5QZ7AmgL2Z%pT0UL#P(l!XyeA6`#<^M@<00Fr4>N0^sP*KG%*b67~MLqH&e;&fpkTcfh6hVp}J zR{5!Ke2;wCy6v@Avzt5q9BqV{MP`7sT6$mFHMy&leSa&b0MBON%thdg2jo$h0 z!nC4;@l0^=Jj)Py;>CEt8YbRbbi82k)`(2YEF{3lw7vqCX3vjL*SqBuj z^4zJ&LL|W*)u4%xliU!t!V-wQGJ+hn$jlW7n9co=S6z7iy~ESiEPnYsZM#mz$NT?s z`GFm+_j50M*6f!m=<3Jk_iq(?{`S|0j&Za5uim?9{Z`a}(6K3?V-e(c&hZ94XVf`@ zf`il=PNj7O2M1+nbwR;A^?Kg(NuO2=eV#nYw>nxZyCQ?Mx?q153HMJi#(Sz#LgONV z9LT_2f#6hj;4c3J!NkDO9-6F&A*1GS$Y|j$BrwdFilZ2VdBs4;idp$!8bsY$n;@!0 zMzJ)8CXE^f(JZ?*@1+IJ`>P&a`qz`v4}F!Fmesvcv8%n|f#rWWP7NQ;>=O39F)nrE z9g8c%eB%H5LeJl$queeu>!90 z$%(cB#{&$HbuKAw*;GltnnOp z$KZiM3T_N|0j9$PhQ24R_5fKp4N1atOqpS_B|LoRdA-TLdgiQEAtwE~ltpnInK@?0zJYYmWDYc7c0c!WKwoZVAKYa7Z^+{0W~D~Fe-);tO|PjMQQ4H($tIX z!bmWpP;5n^eoGk(dh)R|6Fi_stKqd8rqw|%k<;m5T&Q4@2T2pPTE#gSrzd*qAo>g~ zI7u}u%^uOI^*9k!)}?hS66;#{>`NW+35uI^BLu&4a!iGuLXEc9M}vyAAeaU7!CFj0 zkJP3?%6W`-4mU^8*>vID2uRzE5F*thH4a_4J_*VclK8R0IQ3Y~DBWm%5hp8F}8Bz%Ions6F zuk#TiXe1jhgzJiRtGLy|N}UdD8fQ|Q)SjH5Is|5ABh?OF62u>~)y29pu8uRKV}(cp zg9(f$X1)g@ciwwaI{oN9=|QRCeR>UC>l<8Re@5Sz+y*Ffv!QOdXMJii+Zpq7TGd32 zw5l`E)k09i1RiSX_*5Z?q^dOX_;by3k=EZ-PLD(i>IwGH@eW;1m%S&2U~p5#?d&_- zzli%iU;$N<`~x5f4asr_sBu&<)X5Ar=I~kth)yUUOGNbW5LkmhQ3ChDv4DxZ!)i6? z7)~R>b9>?9OcD(_%+B^*1G($C@B4#=p4~sywD0C00LtkFSY2BQE9fc`yK}Y&>R_`sAcbpPW_-fz&Q6=hF-Hz&GDW#iD2PkA2O6^)0J7xJ*ccIP$Yq9FPQc zFl$%e*SL%$?!=zwK+l}JXVyVq6tHJ9UW6q$SX`2)c}mX^>OzQ~#5k$=n{PzVAO6-X z^4Rlac7O*z0anDv2{|n28>kjkP?3OM_S)-UCMfnCM!A>iYlo!=qz4bv*MRA7(QQ%# z7cE-_3G!zWt}K~efZ|x5aIu*F!sq}v2L&8(v!DR+weeTE>tZ>yjCX42QSuT`Q{}ZP z?5j79Og*G2ntI4sG`INAgui(b@Ph?Y;v8d19y1$NkzS_0yQO1dxwM6@0zJk&a~Qt{ zXMLpFIRd zECdsMxPX9JRtq>|P{lZBU|evVJuW0Jw2idUHm*(ErrYP;W^40l^KJ7p&UZO3wCPF7 zz*%?lWgJbCoti3X0{Ag+$iH)4;~)RSUCSSNmcI1TxaS+6e*LHad`~y+TyS!3`LW_{ zXU2!yxx_nGl&yH{=+-5m8u}0Fvg&%RnjU3s4$B;+%dy zP_5Nu(lmMPGIjYs>PxKFNj`c}^veze$`T+%L$#JeB%JRI%@e^&xw5E*-Uro@wQSkA z>Aw3mZQRoTNz|j|=f3#zeCe*3&Q31&?e{~X3`lobe*7WUw1jywy z;Nt+!`;u6vpMIMGUKF;?_oR0dGdF3vFxg;*R9Chita7_^4Q5Q!efMk01`Gg@kGx~b zV}(+m^Z|8H{Lw#!P~f-n1w3(BlALUoqet(dMH*~QXJ^c= z((_+_b*^l;WZJTE%v&LH_IRRF)3%72JrC=O@)UKc^ny+2O zx(FOYF8+AA(=;GJm0ZuD;*0w}Iq_`q$*RiJbETi8_o@Axx4-Y?AK0?-pqX1RM||)l;YRw=?^mIwf&%~xU73X#IN4KTym7p$0L){&36xOf^}FRkm8dg#cfo)fsSy#rMAT0b zt=5pqFj!#~M3$ZT%9UqZ#*|dw6>%~HfQtt%{!X6tlQjq z_4C~Q(-*Z(e0WRLBURmBebv3ZCAO1Gx$w?A7cRW_zI3@y>I?Aih>6;FNWFH!JUW)D zsG5$QIS1{%%sYRXcMu0^p#F)0Y%N{-M`0!`k|_r8OH1!qzpb+~{y^Q+PjManQ@D=S9WOrJzghI`e`4X{kCAJKK~|a2p9WSL zW1PO~4x;bYK1xoBTnEo`byO5`$yBWhDmhYNg(X!U`w6ba2S}fQ4Tf)6h6sbX=R35j zubNg#AJgE@PJUruY;!Zq;3h(niz7#+nam9R7$BcA#u+HU4umE(?O^6^!n6+`;)yXXHXeKiM$lqdVN`KPAS zZ|zwt{tTIr@YvAq_ zz__Z_zF<9k1Ygll<)e;d5kjPD92*DggDI+H^%Rz)nk~*&En}5@rC6z2%~lDk#nq|+ zoa+zC!}NC1PyQ}VqL4vdw6#n0>{~-GN^|T)$$^V9db5~IkuQn`u@1PN(=WHYyJ?(BEI{NoGKd-NmPa`!!ZE}ddO-VboA z0B#M8vrzK7Gs4Ge((o!0=r5|g^i6iw<$uc8tRfbZdYYJLnP$oh@R{b96=uHHmnvsz zEVPY8!RU-p#gVpJv}?zh?jDfabvFpfFgqn0iPLUfxnPcj_T;+0};;CmPv@=qrm~?CEw(p2(6s5x#mDpcEPv(JvB~5yaR5VsoCbN1?@R1#s;ty~YamZ@# z&~g;6qUrwoo3`J7|MoAxzy8&i*RQjW-haF2gAaP%et(bjSLq+1d2i8Z*uE4*V{nXj zNi+E(=okHEqBCH?Uv?RH(bMcyAo$8jvez6ENr2TI2qmy6D^aEr3u8bLZ;35dzVs5h z%+J3#SH6pWvssBNHgE4gD{7mk&yrq|zJf5~>@517E3`n2wn~M3Fsy!JWCIutL^fTf zUH+$iPX)?x%_N9$CJg%Up%@MI*fM z%}XzFBM}4e+5PuTpA8i{7V1sM&YIr*<8_Eqmx3m203KOLK4kn=I;hxUt;R0RDHS9% zi5hGl)TyCAg!IkpI6~r_4l}&F)oig7JGEQjZBI1O9A|M7C!J_^S_()3Eie~Ytn(qG zfqqlwp%NbQ8^+z0bFc&Wc49;3ouk?6m=W*3-v1WA@Pn1>LWiM!>;X*?0hH+vrK&bDP&mpC$|6-tsDaX&Sk7H}z~0Djo4$6TZ?_mVSJAI6T+Qd4Dg`QG(Xw^Cmq#;GK)p%<}(t9lxL?H(O=;t8Kk~nA`EwF`b zpR`~>!-bD8v|~sj{9ZcM+~0QhqMiHCa|@g41RV9iU4MST&qn<&Ej^`2KRyKj(iG|E0{s&VL!hLEP?FTuKZTc=5T~O;WuJ( zP0iFiFK`Zyb5G-GSm_CxMYB&xwO@nBFJcFOY6D#0AAb>W(Nl{vO9$>%tI=XMU#A7M zG?1eZ!S|{JKoXNVfFCAvY(tVcr+zD$142QUfvR+CY67dAl!T6w)Pb3{lJ9TQX?R^Q z38sOZ9}D1N4~)iN>!%CWhZ9JqbK$~pakwf>9i>mY`0rUk;N+zCy4T%C)(X!US%DkgA=movmHU zRSFf_HQYM3nqSA?CETrDr}Y88xpO}hb3YxY+aB9@xa(*kcbHsCC* zn(&lYgTy)45tpMDF`mKvgc8qO`QN90RPy>s5JW|)a$2dnlde{Yka1N(&AN6hKT11? zpQ%*?g&GcXJ93hTUm(@c&K_7Ac&UeWN;R+3;WUC@*#AX;Cw*B;<0f-H(lYumQd$At zV?9u6C2h_ugUx6_wb5}JJw|308|W;7Zy%pL|})HJD1Ta2eX zVEcmsv%prhHOH9c0lKYFX}*F9)0A6M;e&ZeEU*G*fbw8^W{efXH$UEdrbLphh zw4&jJ^uyS^yxj}B`Mkb|*m9)wJjm3{FM^o6*crfZB&cmbYz741ryxRuJQ7cHh?u2C zi|R@vV2Ve!pQ!b69%&5bk(^$m*%);eo1&h@iq&Oosk(vPrPdBfEq%hG``2S{-(23= zJZr}fkL~dF-?8V1=9y3jZF_5VVXyeVYU;4O;0W;b^D<$5lb=_Zl_!3|UgOO~$IFz% zUKDv+{adul3~|vPXG3$2wL;+1+#K)*x)q-yb0942a_07#b84#R&fK0k;l~5ZwmY5M zmmT58I2IcV7OcrM9`g^FVtk|VRult(@J%`i5U4d zUl>EW0Ah>?fJ`KWd6)W9FJVO}paipPjAJ5jbpTkek}FnW0l|h@5`Oj6=KMK#c= z3dzv>L!Dx)fxYIXx!-Ws9uOGdV-E>7Sj8YC1Z@7Kz{eyOSbe4j#9F6@gqlBuJT{~b z;J-4Xkf-iID)`jY&pvw_(j9Qc6@4fx5$=K>7)#23W#~5sV`|%Tqv1Z|eL)+8`DT5y zzR}QVYzz{>stpZBRZ!rA3rHA{qw*@XK8(yxbIvMGOPl=&7X3UlHodL3_HpMpdQhqT z5$B}Mo|T?fT-?{MW(6Uub7~)dyf){~VK=tQ)j+^aNPEgvHW4IT;U?_z2fq$?&VbFx zQ!N8NN4ogT6Dw`NXW&k@Y60Adcijq5?ps=*}yaMYLk3t%+Kz~Sx?BK zMvzS94%v>s@XRmoO#IC|Py;aJ8S@ZmJ8rp?Jmk*1L+_}>A$LA>-8l{1!MtDu$;K;? z6Tb}afI!?ZQ&%iwJ=t|4r1+ww!?Kt$(A5@-X7=&4giB+-f?s1 zmv`LUQSM+rZfI`qoCcZti^!eZT>ZGYBhT$*N(+C6!7uN)G5F;jHwMZb#J~;Bje&9p zF>v2;V<1PhG6uyz!{C>9+!*}wjvE8z4r1VjCSw4WZQsptum=R!yUe~-~dY!cR`%D*$tkd=Wt_53piVOwBxVWlJOklX%hRl??iu8u4=vdej zccgP;eoa+=!5u4vZ{lO3YcqcL;*rgpj;^mMC|F*dm%jpMqCL{9yaV!Io%mhydD%=%U%F=%wEAd`oeB>;m1Oz+}0Bzcz!gansT-5FkG z$DEww#T+80$`ciH%4bekH*wQCS|@GieESl6Uw!q1kJ7ga9i358&!2p+S&D6Mrx%;A zN;d+5tFPW1&+7rB1Tq2YCsMPAa8-_G zz=yha{Gs0*D6o{*+}-;^BEY}8{JrcYAbSAb-Udtbqr%yN>CGu6%ii!aUb=Vg{PAO7 zeX)MY-i`jH`B)&uxy6T9I|{-oXBz=sB^Fm%#5W;E18L@*;Zx-V39H*hupi zrWa@8z=1Tb`O+0wyKy-%%(bK)TzmI3&#t}uY3|0|Paj-!_cKppe6bWpA=cIzpl-+l zI=MyUj6^j{V6$jE?C<*!ww=f&+uaG*x*^!Yls*0-@x!=mdUE@T?eFx$j=P>8%f;Xy zKW2HB%bi_cAmrm4ty~Yq|4~fvw zVG*JjC=N4wM~mi6k{yS`^L5zcc}ZSa13}6D{tE1im3lDpggK&zOdVuV(!9gXrO}c$b#F&lwjZcRytKG2eCsYhB9{|7(? zcP`Ym<-qoAX4cP#+6LWxtyYtv*NWa6t@k@7&v%GL`*!-J;iM<&((tzeFHW<0n)H~L z(D*Sg^E|8HJT03$Nfl--9;XVM9UJ?Z^eJRlu#7tai~xk$IGsbTTro>uLooC`*vtxgjN-C|d0~JGs_C|O10^J=#G}#h!4+iWK&c7ru?`RCig(^$T;MS_ zyta8+{P^hPd%q|zpEG4j=DPRi%$YZL?%en9S^GZx%$qak{d<v*X;X7ws9gF& zZtm3FsZ(Fza~G9Onr{>)jyw8n!3gPHuA}IS(P?j5rvVN~t-BNzVi{P^1LU*W~FU*Q=ayF9@E;l|(X@b#;(dB1k>nRDKc z{~8mP{2IH!J`%Q*FNe{qf|nUpI7gd6?~I^!7PUrg)@alj7NdqylU2_I`i>R`x0l(3 zFAuO77V0buJ;?3cLjHC!womHq0j9_a19)2jxFYaJ18EpJ?=rN`64vj~2Ee-nV7Vep zenA3MQFiRB-Nzl-y7pl0p5*;d@xDL`pjQ^$1Vhl@MgM_`WGRTt0E_hjf0Z4D_(ERC z=YDM+-v}9g&9AQGV|@{K?G@?RZd}GkZ=WV)vj^bqQMfB-9@b|4jVG7YLJ3bx7p~VW5NnE&}dw)4hHGQ&|UmXd3M7*mCZiXg+uD z9NM{J;(#4Em%$38I_>as23Tt%ZKB?&ZL^AIwWk$c*Z^;r;M5wyMC1%4BxKM$!^$YQ zPu#vCdwGu#51R_=J5=B=Swu3hH#wx3+kAcP6X&JFot)Ue`iHeooTXDb`{AubbX<8) zd+$N%OvPIVdr=R-9KqYYV9$aFS>jAKIN;4K@Ub|ICZpM5G8thX8q>8}%oIvlRIQdn z>`w*_W>fTnQ45Jvky~ul8e`FazugV9UL|#O_3G7YIPZcbgdwR3Wl9A_hLAJGa7_NN zFlu8V7Je)2EKQW&fcIm3EVY$&(%q}hQP|4nDv77-r1fyp*T=wkLb>nFqx>P!26+;w z8zsw}V@D1ThYByk8v}#wo<=qzJczaW8C%0!{B}WwVU#`0GQtzmU(iAf46_UuM~Vry z(Uyd;q$s&^?xZ{e2IO5y31#6KQxzx8xIY!`rF;|jd14_0m^ez&)pL;jrLcKjUX_SY zMI?uFNw|U6+m>vjbwL}7c5l{d`!CZUeCuXDwn5;I4IlY^|LP;-o0lB6JHGF$dnRRD zDUHpWgXOW+TcZ2Va~E!#A$=%qDk$SVyG@e*fHkwX-F7~^FNcc1$GXwNg0oYQ2gAt? z{s2?XvPWs{ebTzU5)Mvm)9nLB>c+@kD^%JXC9!O`^0iA(Q^-8pyV!9UzH zy)iHScQe-Rf9!V)ws3V@N;fTE*4R+LY4OITRqOA(*|6?|wkI!@Zn%5d+kbrK%{q*I zA+neE%R>zhtTFp&KGCV#_)iQ1>{J)2pPCQQ6F;NY3@Wc+i~%DY1M+dnpgmMpA-NR5 zBJT#{N(Xk(L$Ur&>BV;G2+eJWoEZmiW+nVeJ`J+qS`rDnHRL^J^i%$ds!c7bcoM1M zB6Kou5`am#ArB%2d83(^02-Ubuf#2DeIGH{wnjTTXzl?zwexdH+Yb9R+>{JJhZH;1 zK8l|*fUcoxK2pUI89ER$2;IZsz^!Z;>=v`IzRT`iakS&B&pV|T4oF94;@&tpUjk#) zhpcmELXDe7uIJO>4}+YWC)T)mW^gLOtpD7qwF#elsTkQ}^r050xDyzx>!#|&GJ___ z+fqhSJxspHPlchqpw@DX02E&V*$lt z%%l%UHRq)}X!9KD{C|{6x&8|^tzk9&*EoGmSZfW?bXqFne-Albc%!Xzgokf1^A?## z&!|;wGHna+-bGHsVn~RuPGb+|h}FF&5+cvN+{rai!KexTFZQK~G;USxM zettn-Zb3ipwC=k3Ipo!&p=x|M8S6BXh!Bmx7~v(FLi|l$oz&pej?fQdunB9J&j=`E z`w-U8<%;nuaACu)r~!AH%ExFkR5%Rb4I5};*c6i~XL9oW!-mD( zUv}he>7$-U&R^bFcCT($e%1Dw1y$R*s#$-Sx_(1_RPcmFueoPe5;)x~8XnIcj$5pgdMBK+&$qaPHhK zyBTHi6>OjUo`@t$lW@e*T<+g}g`A`R1Gc+AjMGXzTj#M>R&aY$-(~FW5$G)idV_Z@ zy#xSFP93EE)O;f+HlkMrD+E&OPJk*s58Sx}pGVl^kM=(-<*N4mus{{`!#@y8!OizT zJ96Po5oyj4ou^UDTR7EMMsF+k75T#0>q&gPw6wyqgn2CSD#tZzoT34LQH!w>O)d&? zIY)>&hAIM-FklQ)z{hWoPc}uV!lpRxm?sq-Y36eu>UT~~6X-^Re#0T|VBciciMXtn zw)44AeBvPSFTp~q^)PIt{4=$J=kbFVJ*r?GOB1eLZ@V{eJs%DPV)YI9ln<|%{|3{j z1dq|lRurwvlA?uWuttDu*h))l!JGXnOjXw7>vM5tIWNX%BlD=De`A5wx__ zIa(tU-(a21D3Zwkgp;pr;r|xD)?4iV3cecfwdI?zmJ#8>p2VhMkr6%y%~IX6V7An= zas*&6S1HPGWKkjoJV90g3-fl_x88EaX&gZJM( zYjWj==H~bfh3i|69qd@ykhpeY=H|4{gZ<06J^iJ8L1vzFT610Cc*(gUJ!4D#`X+wP zys(gU0Rad5_41y`Ye3;;pb+07;*ab0e*f_SnylZDuk|efz9x;27t<^?En`c)Dj~xS z!T=;)6o5g;H`ojy3@+R)7LWu(6f4T>>dMO+>Xx*hKlgO|x${qRPxQ|d*8HFLzC6CE zD)0N8o13KB)1+zICQaI=`<5=WrL18Ste_PgifmFgMOkF0EFvO^wg?D{fFc7}&|y&7 zL_}}_*<~v7xS)bFE{~4lybg32Y18NXJ2$r$#OL$Q`~J&qPi}ITbIv{I-1FPN=h@oY zHP0=seRkUUeQ%sQ_r|{SO~X+e&OnCcN3}bFzSSiZh`Sv1FQ3Dz;s3S+3dLiMp5*dP z^4KQ3CYpfO>zSw>mxOVO(fO4fe@dl-oi4bG5D8gaQcP?E0~$g!P;fB6mIxpmF&Q}A zu8K>uC&0(=GH|#X&>AOCc;1Z$iDEog8S`_p3FmZpaZ;28Y6Y3E)9k5QHgT z%*mLNp^W;W2+oAyQZN2GU=(YA$WTyHP+Cw{&|V(OOGv~PFDSI;G-eXHHra}>48euC zgoA5F8#mX;xKjKW#AmeRFMM(4U3Uzr;6L`Os_M)C9(Hj)`hnZ#7nMEId%{ym84IhQ z-FW1{w2{NwKhmY&Bb^4%NlSj@u5HWt-admS-BrDiFKxGK;o|3Vmf8X-e_U2vyfrJQ z|E-mkTQ~h_$H18nus?luZcZ+EPkWLtATH5ox$TL1zupn(X?M80YC>3G$t5X-J>jDU~_iLFZktYNw z%03ZtW{NL>xw8p~W_C!EcsayC5i<{wq3}uJmil|4_5y!PQ9@iLlPlr(C8Z^ZQZJU$ zt`lwFBV9Up?3mp1y5aVrJG*ijP;^#A+(R-`u>UmZcORrhwump55!fw3AZY{rcaiLh zCBR;Yb{0FM0sTkVfAUA+@RclSDIXnP+dPS8j)8m%Y;(hyz;lwvik#F2nyB@*;RllNLgl=mLm}h}|@43Bw02l8R9N z;la1w5{ywsno~Gq1~j9xc;GBQy)qcq&1;lCpF5&CO?zO$zxQd%Q38Xl{T1lm0&H>U z)+l$PFA+}&w-By(`+SKI{HzwO!|Vo}g2_!#3h`#AQSajk#@$iQrH)@>ciW&?{YBoL zyw>K8O7$gr65`D!M6Vf{Ly5Wp@dtIGp-sR!~?LRho z6X!e}KDxAdVYu-dSL`N#^3$uNmzVO2SC2X{t_Si$^vb)SEM@GLPCe z(|FT*2a8{Cm9vx9mt?HZ_qH!A@Um=cdm)Ysu?n0sY^k4hBDftvbt1zULIlyp>l;>` z*E#1dhBEDUjIOsBW69`R5i!T!F|zR1B^9?l*?;)M+=MedAJ@G5vM|S{#B~g9>r@t- zB%4Y*h5zzO$M(gr)Vn)%+t#J5j7+o`&@I1!f_Y(2a#(g?21P z1KdmzHO#upT>Ec+g&}|n-a!y9C{ja=FU0J^5lzVW5d$h*5EOq2gmW3BWSyjI04UAU z@G|L3?b2T+$?skfUcWPdKH`uAC>QvTA-6#?$xV8;)hd~_24>VxH*45*EuqAbeOmAu z#D##S5I>6Pod7_Tozz#Th;lS*mAxD|5WX0`cz|!{&o{Jw74sI#9P(?KX01^p%G5@2 zvz|`}pE_OfXKwAmHf4$u5h6eZbLmljCY%Gs)ah^s^_v_B59=Qub^spl<^#WeMcX0> zMV`kAS4|Jj1={i`nQbs4S|(8&m1y9Jq<6=QPp^KEbZCe}Cnv&4s)W*`xTz^TMnPXA z1U5>rEGl+%vizo!9tXUr4wDO6ew8z1`Bl$oBWD!LFP$lh+#}9l^!Gt6-^Q$NM|4HU zkl(t>9Bo_`wb;#8nP27Z=qM@1X7a@uEG#d^r%ezDBABn~1y)>z2`>zccR`vfnb49P z$#`9(DS_pRw!@tvT7J8EWB8Lx7kQ@CAFz6T;QJGPwYK)v&M@5c>*jk39dI z@TPG6*YbR{nHBuYUctY_vi59jsJtjB_*!>*lBvC$CDr@zowtNM@+xmDdmdr*hFJUkeR;(=|O!~YEbb2ESR&W+1Tinr!u z_2}NS8%GEVg`#xn)}fbB3{~(w3|FwY)aY`AuKHf^v8_`%`P*@n*bOx7%@msV2~;xL!>?`0LBe~ zVzuH^^K8?>H6y|$;lry(Xbzv^4~8E;B|b5-DCed~&KdAH*KE|WU2q(VfEXs~$?k-| z6ZQ|^r$-QZ3;ZIeO$o(_H62=wyr~3T%=-jw_`djrPWTk^&J%e9iI8p7>_VofF^~}> z6$Q&LDkvSN+apy&yIg&zW+S6J@h<)rQ&B3U;v)qU2RM*D4XxG0$oq^ZlEO?5>!LuH z0d37^;Pu86i4Yb%&W8u_ZsWZm>PvwMT67P;a0y%ZK2rGb+Dn>G8aD_n(zI|u9-<>3 z89hr0MZ-B0AZ}3#C=HMwAV7=ARhoSvf)yC_(!Jq%d_IN0@QYz{*rJ`^bgJpFrd&?D za`wt;IS+Gz@ScO7JA(~T-gu^3@|9VFJajrm<^otu;GuI(WZ?f5zN3T{6W*2k%H1(~ zf^2>$At~15wr1v8;(Q)Mwi#ADmrd3fTKsMg!F^|FTCyy81^%qmB#YZ&P0mQw*<6ln zUmR?GY-X(0QKOrgnUo5>B_g>H%Sc}Dif&f03&b*rrfofm19VVLR|TJG%G?5;3?Qxg zh#rU(wIqO-Wt1szt!C7m!Gq?`9W;1OT>YSWU!u>yWmtXw;G%-z1)GM{`xE`j@8bMn z(t<&=XAc@O_d!0jerSE+(1N1DdG*6K6V~#^LG{H$^NWV&)!)4ZziE^WVoMM#Omr>* zm=|&r+p347?R1KD6q-QHNv#A;6Z{PYLk^peLyek)Rzo>xiC7^A6%z|ND0GQ$x*jzm z+84m=UWWGser)7r5Mzjy9M;`NZJjI~WNYQM#&_&yUA#fIz#Uk&LEpwJoV{Gpy%0-> z@E&1r5avWuv2^<82SOQExHpuIL5-L`$RU{QNuxt19$~ZB%-geP#?F!bq!oL@X?u3nugX8EegU=YUg6zLjk+qp|OIW)F3b{>K!weT^Q#&2LAzsIoWze zTYANcN|6nOCT*okR3kx*3OH3l)JD`NQWv=l0b+<0OADV>Y7+DBAGEVkl_hQJp?a2( zMaJ*Y9cT8a<5nY#trlORl z7%0W{Bv}qdd``&kM0lX^3FpE?_@*_Ie>L9(Ka}P#(c9liLFsGFaP*Vwb?D~!E=<@e z4l9NXd9nz6I4qn1WVp7-unF5SiS6Nh_wUVP*I>h9UWOY7P~pUkpS@E|%eWuj{{L@N za|B=RR0MlgPjd>a+|S@yY~ZOgSTXC0HPxnK6$L5H4}Pe#<%rXNq;LD5m zZ=v)u{gIpFH8)8e+VM>0wRfnzX;!<+kg+m$mRxC1smz~c_g027g9m>&s0tAR=Ud^p z#aOsdbOBlwF(61$g%MKV1lV=kkPUqs|Aw}3g>8@j-t~Rb+5IM)N9Puy>1#lqNj3b^JW~9%7BYLyt$%x^~hd5 zMppN#c>x!0sn?wDRb4F(%%sb}uh1Eho;a|Q@&0DP zro9C=Z5=FlW<*fHstqV>laA;EkvQxFq4zU-~$WoIBmACUYj8f$m$tR?gI zrAx@!uT9i!ho_*2y%9=g4!zYRbBEq$k{u`F_3{aq$!ml9U+=1n)mKKrDGMB!Y9Rbj z$gp^ETL0B5n1ylOE2`jy^NJEA4+FW4BIocM4TR$nvv{bhftihFli6&tne4V`o5SX` z#n@c7Sex76iD&WLWAvCjW{<^V_1HXiPqfG3ar$HYE`Mx-JKp1mZ*7JW*B%h6J_;x! z6;H8H2uh>MUCGw;RA~+$GdLrZhF_M9R6bYy(he$%aaP>EXr(t<{epqdJ8MU1R%jbB zCq)zA3~m^p)hCFTpw0qk)>#_R{F1hDC9Vx>vosrYeITK>e;ue98g!7Jy>3Nw@k&Nf zlAn>T{~{z*rFqZ-R?#w6xDYBW!;9Nim^h=}Ggq?Nj!In|>VJ{yPrIwTH%>f69PEvehajg4JRE+bNE}y- z6zd2mW(;AviYRh5v!9%gi|w<;KZIYBvS zvhYSaS;h{7&S=>S`4#B?Apr!oi$A@mZ`PEO&IA4V z`8L}^qp@me0dzH2&mul|!FzvnoOir6JcCf)mRDl2x#nliP7GfF^r6)8z6t9vHbit2#VEUATS<-qt^;6x z5UOn5ZKqIWlR4Jr)aYX5Xr{AS46)$6PBe8oQ3O>4k$akbMdUJB@FA_^)u7mAfYOLC zaa5!=hWSh-pDhBJJ649LMWUH`YQsbxB?Xr??>{>s{39rpK(G?@wKPIOqEJcFw48x< zLMMEl;a`AF&(6~hX9OmUxCg2>Y78{t2N8|KdCK?O9EM};rLt2zRbDII!Bn*B?If}R=9c?v8p>ZW**1CSP0%G%Iv z4!6_6nZ;_e%h43B2A9k@x62*lii>l1Pl%6m#W;1bK)PbFzB+Sioo=-`c5Sx96{pFF zamH$r4M6s_vE&Sgrf0IlAV5|`-wSaOQll_t|8RnsMGOt$$aAg25}Ia;@KXJFRCNxV zr?nYn8O822H`a<#3@vykG3iJr5ADA4^;cJ}oKFeZlKZ5Gzw`aL`|LcPoV+d2Kkv!a zD;GbuvV%7GVfc|F&_#aCGochTKv-IY6JMCFm?!$yR$$jJwX0WExR!f}k2U->ju z7FRhQMSiEq0#$w&aTjPu;-8k_t&GB3(ry=DQQe2GAJzTCHBsFP#`=E})vZ6; zy#2ai-LR`jd2)^Pk)ZC^u698Xsfv@(N6@u!EV8&w?kL|03Yj1B8VULr<`jhdYBd5Z zOb=j9ZqP|Wl@rmrV1}WojKk&%aRTTZz@i-%-Y}I9<9AODZ{S0w!e46>l*B{$uxa>B zAK^_i=o*yB2TIR^_c#aZO?fvH-f+f2>0q~qR~pZ34wzj)A&dRzOP@u%D_=Fz_iZ!8FtK;c-7^AFF^SH~ZfrAjd^Tl8hET||O zLq~aUB0$#^YDgSYNtx=?5(yc@Fw*nC@iondz8!u0sQ!hMx^}DS_{7$V85-;434g7g zRouC6YU*6Ccj5izGp13EZ<3a1o<)r_*^q94`C(2}&BcuPG;kBXS@2DVFkJ)OFHGPN zjLeHFI|EN+i3Y5E5EDNy-9Ar)B^t6&Z|J1K$ig3AsX4v&SO}_hiH0`jBQiH*RueBY zUhZFOFP$AWa{sFxCU@*LDR1=j3FEt03>`7ND))hoy`~i{-!f1h?iyD)XOSzW#*=V+ z&x*d|x^`;cHO^fV?U+8Y_fWjc9$-uk(or}Z=S z>X66JEs597Lty#}`jQ>V-Gs&@nk4XUz_(_QhXR$$01_l&Wc~k0Qy><50vHP`aO_JXXL_1xS zQP(@(;p~%!*9J70Rhh8?{SMuB<0{S5 zfz|DbGcyXa^5SB#aw9^c(^+1;#qG2fWjK9)ojb1`y);EXz${Dcf`4M&$SaT(u6T*i zY-l)@AvlBfD{wmCs-muLrHA9O5&(cNN(_LoX);ZqtQZ~&CGE;e%K~Mm3%KLlohvH3 zKY#0!+v50_g}@aDo-H3+7(VUZw&J$udh}WOhrfn@%-vQv4F)!xt1r~-(At^MTqajf_xe9{LAdGh{U49hDKuADHh9Hes0 zRL-@Ka%%b4N^qfc8?$kvWYiEQfgkVz>MBEkq_uH6NC$KjaY|yw`n_MT(Kd!JqZWQV z`*!Vj@J?(9`C{!r357wE0h8f`+w45yiSpUW+b=dwZ}5q!J;DZnnkI3_W zw?8h~#%&T-1(j`DB_l-@V2e{87toqoKj0Vq7E%Dv4TOpi(Eud!fY8}RQ~;fMs}3OE zZw_S6z2^_9oeRrj12%u=TxramDV?ir%IEOdzOKZ4hgA zWs5btY*_q2kuQy>>t3j@I}Q2LxP5yV*f-3>FUx~8_u<`*55bQLfe=`mfzzubrXZ5f zg$lPgPEN(O}g(o9WE3_)P z5)fY?qCyGfju@$c3vMJZ>L*JxHcXxRcz7;f5Wc`2+H=j{Ox(M-28*wZL~hUq=`ejtS&t5n6?sId+Eq(jldRyh~{qMN*4+E+O-Zg0OkfFow9$w8xj2tz3%suyx zz3={U<0njfVAA9%Q>RUzF|%gY>^XBEocGZDhZj7uaM7cSAA7vEZpjl%mo0yC#mc9i zUiHlCHEW-JZr$_i|F~h}rWfirZ+Y>hKW+WjB?0a+nfw$g% z=iP&c-aCBc=&|D`PQHKYFAeO2(;uGsua7?d&wypR^ah zd25gIB$z|6@$Qi;wz7@v5w?)M2}$N#wg^_;TJ{`!k!?b!Kh8b@uF(o`lRty=g4_?B zvCr8**gC9w|4)>5iEUtihWvP#ZDS+YNVbfP0`|ygc7z>cr`QSDa^GkF&Bm|~*k4!! zdzszCeqzhn8Frd|h`9Rifu8pmyN``!_XG279Gk$_vx#gHgP$v#!ltpQY&x64zGE}l zELOv2V}biQY!CY*n}^|^!?^zAz$*X?Gnv4i-&lkFnZ1NJa`hdmlO_a|C|PHbD)8thlI3*y&4yq+6s#P+7Iqwe326v^*CP$Y_Z3K^kiNt3 zF-QxM8j+qsdJKt?vOga`sqH<7w@q7;KDgS3thf~<2etZ!2eUQ)wK+09>`Zo6OBF&B@ z^*imiBke_k{|Q@7zpFvuHMCZ^(qWr$t--~n{>2tIx)dzdg22?Lf zRBw6?^_i&t3x6k3-fA7yJ=L#mQtL+bYn$kJ+q41o&cQLNH$QajzA7>hB69x{vw^ZBAoP+}ja*$`|>x z{DS=qB=Bl&G(%?@i z&tv)UuPH!0a}gxJcC3V9X-rrz%RvD<@^GtAa<nTzso>Po&Uq$UKY~JSWScN+*R#!R3+UQQ>`!bf zsMa>nqgU9gf-VpxAgZv3y$*`<2HOW}xSt(hZ?U&Q8{P%AIKjEg@KLlOPDrQ}3;L;NH;_tPhNyJa*!! zk)tO}9X)yUD7n|P$rH6BOWT!{(`RXc_$(Bk?dh{j94RXj-^;|Oa=b)*SF|>17%%j9 z3;O9e)>S(x&61W&Z%W^3N;M-i^E6Lk)%k<+qw;pGQ9D+?i}TO*7=thQ_N#AyIi-q7P;Pu zHO1Z;yVh-YSGec9566v*`!aq&{Ob5{f-7N8!oGx~o{^phJaavddscZid0zGG_Z;_p z?D^XBv!}&t_QreDy~W;;x1V>A_a5(5?|knQ-nHH>-d)~zyr;aMdB00^B~~VGPrTx* z^KJEg;;-{Mh`e{E7KX^4|=O4o(iv3)Tf!2kV17f^P*+20smc8@yP+ z3#yW#D| zxBGLu#u9T$uacQ14W;F!6{Ukq$CcKUE-GD7y1w+!rF%;cmws6KWm%W9JIltEU2Gq0 zKe;@r{Fd_C@(;>??2y{w)()eD#9+bOug81$fzv zT$X9wqN_H{Y8*4*GR$bQwzmu;bGW;*m+oLoq%lzvycU39j71jZhZuX=&XN@EBXa3J zcIp(AmvjZI283hy8vS?LizAkVfSzshA8f?Jm$<=pMPngng;)IE~5}L!7 zmeQ7%aA{Hd{sjdLnTZV?Hn#&cl4);jY6~!ei`CuO)D~bSJ(MIjHnjzq`9^!FZ9#ix ziGrH<#-_Fav)*VAwJm6mmK2qdnBdz@Ek1 zVEDhWsV%?~>{u4(#-_Fa^W10;wJm7RywTAt`o^ZV04Y)_UVwZcgl7rax4wGevA^GK l>vW0v5lDb-?^_qviv2s|v@MNTdG!IPZ6CGvje*jesGp7Im diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index cb5dd648f8..0383c99427 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -35,7 +35,7 @@ - + From f1f9173f2430167024fe93909809987a98cda7e7 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 15 Jan 2013 00:53:32 +0100 Subject: [PATCH 0070/1483] Prevent closing dialogue window when an answer is expected --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f9d8c34596..8692573b4a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -381,6 +381,10 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { + // Do not close the dialogue window if the player has to answer a question + if (mIsInChoice) + return; + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); // Apply disposition change to NPC's base disposition From 82287445af3d8667fe68e94e1e709becff02d947 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 15 Jan 2013 00:59:48 +0100 Subject: [PATCH 0071/1483] DialogueWindow: do not execute onFrame() when not visible --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index f62bf2a05c..c7918ceb78 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -490,7 +490,7 @@ void DialogueWindow::onReferenceUnavailable() void DialogueWindow::onFrame() { - if(mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = std::max(0, std::min(100, MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) From 30534404621cdce5ee9c04e027345af2a4a310ae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Jan 2013 12:40:44 +0100 Subject: [PATCH 0072/1483] Issue #539: fixed AiWander --- apps/openmw/mwscript/aiextensions.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 35243533c8..8402a5b4cd 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -181,10 +181,14 @@ namespace MWScript runtime.pop(); std::vector idleList; - for (unsigned int i=0; i Date: Tue, 15 Jan 2013 11:10:41 -0800 Subject: [PATCH 0073/1483] Use typedefs for some maps and some cleanup --- apps/openmw/mwrender/actors.cpp | 124 ++++++++++++++++++-------------- apps/openmw/mwrender/actors.hpp | 18 +++-- 2 files changed, 80 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 05bb030d70..92f5cbe28d 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,41 +6,42 @@ #include "renderconst.hpp" -using namespace Ogre; -using namespace MWRender; -using namespace NifOgre; +namespace MWRender +{ Actors::~Actors(){ - std::map::iterator it = mAllActors.begin(); - for (; it != mAllActors.end(); ++it) { + PtrAnimationMap::iterator it = mAllActors.begin(); + for(;it != mAllActors.end();++it) + { delete it->second; it->second = NULL; } } -void Actors::setMwRoot(Ogre::SceneNode* root){ - mMwRoot = root; -} -void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){ +void Actors::setMwRoot(Ogre::SceneNode* root) +{ mMwRoot = root; } +void Actors::insertNPC(const MWWorld::Ptr &ptr, MWWorld::InventoryStore &inv) +{ insertBegin(ptr, true, true); NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors); mAllActors[ptr] = anim; } -void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ + +void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) +{ Ogre::SceneNode* cellnode; - if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) + CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell()); + if(celliter != mCellSceneNodes.end()) + cellnode = celliter->second; + else { //Create the scenenode and put it in the map cellnode = mMwRoot->createChildSceneNode(); mCellSceneNodes[ptr.getCell()] = cellnode; } - else - { - cellnode = mCellSceneNodes[ptr.getCell()]; - } Ogre::SceneNode* insert = cellnode->createChildSceneNode(); const float *f = ptr.getRefData().getPosition().pos; @@ -51,13 +52,13 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ f = ptr.getCellRef().mPos.rot; // Rotate around X axis - Quaternion xr(Radian(-f[0]), Vector3::UNIT_X); + Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X); // Rotate around Y axis - Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y); + Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y); // Rotate around Z axis - Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z); + Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z); // Rotates first around z, then y, then x insert->setOrientation(xr*yr*zr); @@ -71,30 +72,30 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr){ insertBegin(ptr, true, true); CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr); - //mAllActors.insert(std::pair(ptr,anim)); + delete mAllActors[ptr]; mAllActors[ptr] = anim; - //mAllActors.push_back(&anim);*/ } bool Actors::deleteObject (const MWWorld::Ptr& ptr) { - delete mAllActors[ptr]; - mAllActors.erase(ptr); - if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode()) + delete mAllActors[ptr]; + mAllActors.erase(ptr); + + if(Ogre::SceneNode *base=ptr.getRefData().getBaseNode()) { - Ogre::SceneNode *parent = base->getParentSceneNode(); - - for (std::map::const_iterator iter ( - mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter) - if (iter->second==parent) + CellSceneNodeMap::const_iterator iter(mCellSceneNodes.begin()); + for(;iter != mCellSceneNodes.end();++iter) + { + if(iter->second == parent) { base->removeAndDestroyAllChildren(); mRend.getScene()->destroySceneNode (base); ptr.getRefData().setBaseNode (0); return true; } + } return false; } @@ -102,57 +103,70 @@ bool Actors::deleteObject (const MWWorld::Ptr& ptr) return true; } -void Actors::removeCell(MWWorld::Ptr::CellStore* store){ - if(mCellSceneNodes.find(store) != mCellSceneNodes.end()) +void Actors::removeCell(MWWorld::Ptr::CellStore* store) +{ + for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();) { - Ogre::SceneNode* base = mCellSceneNodes[store]; - base->removeAndDestroyAllChildren(); - mCellSceneNodes.erase(store); - mRend.getScene()->destroySceneNode(base); - base = 0; - } - for(std::map::iterator iter = mAllActors.begin(); iter != mAllActors.end(); ) - { - if(iter->first.getCell() == store){ + if(iter->first.getCell() == store) + { delete iter->second; mAllActors.erase(iter++); } else ++iter; } + CellSceneNodeMap::iterator celliter = mCellSceneNodes.find(store); + if(celliter != mCellSceneNodes.end()) + { + Ogre::SceneNode *base = celliter->second; + base->removeAndDestroyAllChildren(); + mRend.getScene()->destroySceneNode(base); + mCellSceneNodes.erase(celliter); + } } -void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){ - if(mAllActors.find(ptr) != mAllActors.end()) - mAllActors[ptr]->playGroup(groupName, mode, number); +void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +{ + PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + iter->second->playGroup(groupName, mode, number); } -void Actors::skipAnimation (const MWWorld::Ptr& ptr){ - if(mAllActors.find(ptr) != mAllActors.end()) - mAllActors[ptr]->skipAnim(); +void Actors::skipAnimation (const MWWorld::Ptr& ptr) +{ + PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + iter->second->skipAnim(); } -void Actors::update (float duration){ - for(std::map::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++) +void Actors::update (float duration) +{ + for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++) iter->second->runAnimation(duration); } -void -Actors::updateObjectCell(const MWWorld::Ptr &ptr) +void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { Ogre::SceneNode *node; MWWorld::CellStore *newCell = ptr.getCell(); - if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { + CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell); + if(celliter != mCellSceneNodes.end()) + node = celliter->second; + else + { node = mMwRoot->createChildSceneNode(); mCellSceneNodes[newCell] = node; - } else { - node = mCellSceneNodes[newCell]; } node->addChild(ptr.getRefData().getBaseNode()); - if (mAllActors.find(ptr) != mAllActors.end()) { + + PtrAnimationMap::iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + { /// \note Update key (Ptr's are compared only with refdata so mCell /// on key is outdated), maybe redundant - Animation *anim = mAllActors[ptr]; - mAllActors.erase(ptr); + Animation *anim = iter->second; + mAllActors.erase(iter); mAllActors[ptr] = anim; } } + +} diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 073c5d51f1..efb6247e42 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -10,18 +10,22 @@ namespace MWWorld class CellStore; } -namespace MWRender{ - class Actors{ +namespace MWRender +{ + class Actors + { + typedef std::map CellSceneNodeMap; + typedef std::map PtrAnimationMap; + OEngine::Render::OgreRenderer &mRend; - std::map mCellSceneNodes; Ogre::SceneNode* mMwRoot; - std::map mAllActors; + CellSceneNodeMap mCellSceneNodes; + PtrAnimationMap mAllActors; - - - public: + public: Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); + void setMwRoot(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertCreature (const MWWorld::Ptr& ptr); From 8a073c113e277c65fc92598b451de6d336c95244 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Jan 2013 12:07:15 -0800 Subject: [PATCH 0074/1483] Use const references where appropriate --- apps/openmw/mwbase/soundmanager.hpp | 14 +++++++------- apps/openmw/mwsound/soundmanagerimp.cpp | 16 ++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 18 ++++++++---------- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 0c706ab496..5d396fac07 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -84,7 +84,7 @@ namespace MWBase ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - virtual void say(MWWorld::Ptr reference, const std::string& filename) = 0; + virtual void say(const MWWorld::Ptr &reference, const std::string& filename) = 0; ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. @@ -92,10 +92,10 @@ namespace MWBase ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const = 0; + virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const = 0; ///< Is actor not speaking? - virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0; + virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0; ///< Stop an actor speaking virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; @@ -105,14 +105,14 @@ namespace MWBase PlayMode mode=Play_Normal) = 0; ///< Play a sound, independently of 3D-position - virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, + virtual SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal) = 0; ///< Play a sound from an object - virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0; + virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, - virtual void stopSound3D(MWWorld::Ptr reference) = 0; + virtual void stopSound3D(const MWWorld::Ptr &reference) = 0; ///< Stop the given object from playing all sounds. virtual void stopSound(const MWWorld::CellStore *cell) = 0; @@ -121,7 +121,7 @@ namespace MWBase virtual void stopSound(const std::string& soundId) = 0; ///< Stop a non-3d looping sound - virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0; + virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const = 0; ///< Is the given sound currently playing on the given object? virtual void pauseSounds(int types=Play_TypeMask) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 8a69fc96bc..c502906808 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -160,7 +160,7 @@ namespace MWSound return volume; } - bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const + bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const { SoundMap::const_iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -229,7 +229,7 @@ namespace MWSound startRandomTitle(); } - void SoundManager::say(MWWorld::Ptr ptr, const std::string& filename) + void SoundManager::say(const MWWorld::Ptr &ptr, const std::string& filename) { if(!mOutput->isInitialized()) return; @@ -269,12 +269,12 @@ namespace MWSound } } - bool SoundManager::sayDone(MWWorld::Ptr ptr) const + bool SoundManager::sayDone(const MWWorld::Ptr &ptr) const { return !isPlaying(ptr, "_say_sound"); } - void SoundManager::stopSay(MWWorld::Ptr ptr) + void SoundManager::stopSay(const MWWorld::Ptr &ptr) { SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -328,7 +328,7 @@ namespace MWSound return sound; } - MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, + MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::Ptr &ptr, const std::string& soundId, float volume, float pitch, PlayMode mode) { MWBase::SoundPtr sound; @@ -356,7 +356,7 @@ namespace MWSound return sound; } - void SoundManager::stopSound3D(MWWorld::Ptr ptr, const std::string& soundId) + void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) { SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -371,7 +371,7 @@ namespace MWSound } } - void SoundManager::stopSound3D(MWWorld::Ptr ptr) + void SoundManager::stopSound3D(const MWWorld::Ptr &ptr) { SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -418,7 +418,7 @@ namespace MWSound } } - bool SoundManager::getSoundPlaying(MWWorld::Ptr ptr, const std::string& soundId) const + bool SoundManager::getSoundPlaying(const MWWorld::Ptr &ptr, const std::string& soundId) const { return isPlaying(ptr, soundId); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index b475449d90..2af26d3dbb 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -14,8 +14,6 @@ #include "../mwbase/soundmanager.hpp" -#include "../mwworld/ptr.hpp" - namespace MWSound { class Sound_Output; @@ -57,7 +55,7 @@ namespace MWSound std::string lookup(const std::string &soundId, float &volume, float &min, float &max); void streamMusicFull(const std::string& filename); - bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const; + bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; void updateSounds(float duration); void updateRegionSound(float duration); @@ -93,7 +91,7 @@ namespace MWSound ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - virtual void say(MWWorld::Ptr reference, const std::string& filename); + virtual void say(const MWWorld::Ptr &reference, const std::string& filename); ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. @@ -101,10 +99,10 @@ namespace MWSound ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const; + virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const; ///< Is actor not speaking? - virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); + virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()); ///< Stop an actor speaking virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); @@ -113,14 +111,14 @@ namespace MWSound virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal); ///< Play a sound, independently of 3D-position - virtual MWBase::SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, + virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal); ///< Play a sound from an object - virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId); + virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, - virtual void stopSound3D(MWWorld::Ptr reference); + virtual void stopSound3D(const MWWorld::Ptr &reference); ///< Stop the given object from playing all sounds. virtual void stopSound(const MWWorld::CellStore *cell); @@ -129,7 +127,7 @@ namespace MWSound virtual void stopSound(const std::string& soundId); ///< Stop a non-3d looping sound - virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; + virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? virtual void pauseSounds(int types=Play_TypeMask); From 9e00c6694fac95cf66e360ee3905abd5e59c1814 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 15 Jan 2013 21:40:44 +0100 Subject: [PATCH 0075/1483] Allow only ID filtered topics for dialogue with creatures --- apps/openmw/mwdialogue/filter.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 7c590c8ef2..99be5554a5 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -19,12 +19,19 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const { + bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); + // actor id if (!info.mActor.empty()) + { if ( Misc::StringUtils::lowerCase (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor)) return false; - - bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); + } + else if (isCreature) + { + // Creatures must not have topics aside of those specific to their id + return false; + } // NPC race if (!info.mRace.empty()) From e5f040a06f1ec85beb05a547cae8fce1fa4b3815 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Jan 2013 14:10:52 -0800 Subject: [PATCH 0076/1483] Improve filename pattern matching --- components/bsa/bsa_archive.cpp | 307 +++++++++++---------------------- 1 file changed, 104 insertions(+), 203 deletions(-) diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 9913fb8aab..5274564a63 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -31,150 +31,30 @@ #include "../files/constrainedfiledatastream.hpp" -namespace -{ - using namespace Ogre; -using namespace Bsa; - -struct PathPatternMatcher -{ - PathPatternMatcher (char const * pattern) : pattern (pattern) - { - } - - bool operator () (char const * input) - { - char const * p = pattern; - char const * i = input; - - while (*p && *i) - { - if (*p == '*') - { - ++p; - - while (*i && *i != *p && *i != '/' && *i != '\\') - ++i; - } - else - if (*p == '?') - { - if (*i == '/' || *i == '\\') - break; - - ++i, ++p; - } - if (*p == '/' || *p == '\\') - { - if (*i != '/' && *i != '\\') - break; - - ++i, ++p; - } - else - { - if (*i != *p) - break; - - ++i, ++p; - } - } - - return *p == 0 && *i == 0; - } - -private: - char const * pattern; -}; - -struct FileNameGatherer -{ - StringVectorPtr ptr; - - FileNameGatherer (StringVectorPtr ptr) : ptr (ptr) - { - } - - void operator () (std::string const & filename) const - { - ptr->push_back (filename); - } -}; - -struct FileInfoGatherer -{ - Archive const * archive; - FileInfoListPtr ptr; - - FileInfoGatherer (Archive const * archive, FileInfoListPtr ptr) : - archive (archive), ptr (ptr) - { - } - - void operator () (std::string filename) const - { - FileInfo fi; - - std::size_t pt = filename.rfind ('/'); - if (pt == std::string::npos) - pt = 0; - - fi.archive = const_cast (archive); - fi.path = filename.substr (0, pt); - fi.filename = filename.substr (pt); - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } -}; - -template -void matchFiles (bool recursive, std::string const & pattern, file_iterator begin, file_iterator end, filename_extractor filenameExtractor, match_handler matchHandler) -{ - if (recursive && pattern == "*") - { - for (file_iterator i = begin; i != end; ++i) - matchHandler (filenameExtractor (*i)); - } - else - { - PathPatternMatcher matcher (pattern.c_str ()); - - if (recursive) - { - for (file_iterator i = begin; i != end; ++i) - { - char const * filename = filenameExtractor (*i); - char const * matchable_part = filename; - - for (char const * j = matchable_part; *j; ++j) - { - if (*j == '/' || *j == '\\') - matchable_part = j + 1; - } - - if (matcher (matchable_part)) - matchHandler (filename); - } - } - else - { - for (file_iterator i = begin; i != end; ++i) - { - char const * filename = filenameExtractor (*i); - - if (matcher (filename)) - matchHandler (filename); - } - } - } -} - - static bool fsstrict = false; +static char strict_normalize_char(char ch) +{ + return ch == '\\' ? '/' : ch; +} + +static char nonstrict_normalize_char(char ch) +{ + return ch == '\\' ? '/' : std::tolower(ch); +} + +template +static std::string normalize_path(T1 begin, T2 end) +{ + std::string normalized; + normalized.reserve(std::distance(begin, end)); + char (*normalize_char)(char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char; + std::transform(begin, end, std::back_inserter(normalized), normalize_char); + return normalized; +} + /// An OGRE Archive wrapping a BSAFile archive class DirArchive: public Ogre::Archive { @@ -182,37 +62,12 @@ class DirArchive: public Ogre::Archive index mIndex; - static char strict_normalize_char(char ch) - { - return ch == '\\' ? '/' : ch; - } - - static char nonstrict_normalize_char(char ch) - { - return ch == '\\' ? '/' : std::tolower (ch); - } - - static std::string normalize_path (std::string::const_iterator begin, std::string::const_iterator end) - { - std::string normalized; - normalized.reserve (end-begin); - char (*normalize_char) (char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char; - std::transform (begin, end, std::back_inserter (normalized), normalize_char); - return normalized; - } - index::const_iterator lookup_filename (std::string const & filename) const { std::string normalized = normalize_path (filename.begin (), filename.end ()); - return mIndex.find (normalized); } - static char const * extractFilename (index::value_type const & entry) - { - return entry.first.c_str (); - } - public: DirArchive(const String& name) @@ -273,15 +128,20 @@ public: StringVectorPtr find(const String& pattern, bool recursive = true, bool dirs = false) { - std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); + std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); StringVectorPtr ptr = StringVectorPtr(new StringVector()); - matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, FileNameGatherer (ptr)); + for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();iter++) + { + if(Ogre::StringUtil::match(iter->first, normalizedPattern) || + (recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern))) + ptr->push_back(iter->first); + } return ptr; } bool exists(const String& filename) { - return lookup_filename (filename) != mIndex.end (); + return lookup_filename(filename) != mIndex.end (); } time_t getModifiedTime(const String&) { return 0; } @@ -289,21 +149,44 @@ public: FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, bool dirs = false) const { + std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - FileInfoGatherer gatherer (this, ptr); - std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); - - index::const_iterator i = mIndex.find (normalizedPattern); - - if (i != mIndex.end ()) + index::const_iterator i = mIndex.find(normalizedPattern); + if(i != mIndex.end()) { - gatherer (i->first); + std::string::size_type pt = i->first.rfind('/'); + if(pt == std::string::npos) + pt = 0; + + FileInfo fi; + fi.archive = const_cast(this); + fi.path = i->first.substr(0, pt); + fi.filename = i->first.substr((i->first[pt]=='/') ? pt+1 : pt); + fi.compressedSize = fi.uncompressedSize = 0; + + ptr->push_back(fi); } else { + for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();iter++) + { + if(Ogre::StringUtil::match(iter->first, normalizedPattern) || + (recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern))) + { + std::string::size_type pt = iter->first.rfind('/'); + if(pt == std::string::npos) + pt = 0; - matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, gatherer); + FileInfo fi; + fi.archive = const_cast(this); + fi.path = iter->first.substr(0, pt); + fi.filename = iter->first.substr((iter->first[pt]=='/') ? pt+1 : pt); + fi.compressedSize = fi.uncompressedSize = 0; + + ptr->push_back(fi); + } + } } return ptr; @@ -312,9 +195,9 @@ public: class BSAArchive : public Archive { - BSAFile arc; + Bsa::BSAFile arc; - static char const * extractFilename (BSAFile::FileStruct const & entry) + static const char *extractFilename(const Bsa::BSAFile::FileStruct &entry) { return entry.name; } @@ -330,13 +213,13 @@ public: void load() {} void unload() {} - DataStreamPtr open(const String& filename, bool recursive = true) const + DataStreamPtr open(const String& filename, bool readonly = true) const { // Get a non-const reference to arc. This is a hack and it's all // 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 = const_cast(&arc); + Bsa::BSAFile *narc = const_cast(&arc); // Open the file return narc->getFile(filename.c_str()); @@ -360,32 +243,51 @@ public: return findFileInfo ("*", recursive, dirs); } - // After load() is called, find("*") is called once. It doesn't seem - // to matter that we return an empty list, exists() gets called on - // the correct files anyway. - StringVectorPtr find(const String& pattern, bool recursive = true, - bool dirs = false) - { + StringVectorPtr find(const String& pattern, bool recursive = true, + bool dirs = false) + { + std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); + const Bsa::BSAFile::FileList &filelist = arc.getList(); StringVectorPtr ptr = StringVectorPtr(new StringVector()); - matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileNameGatherer (ptr)); + for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();iter++) + { + std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name)); + if(Ogre::StringUtil::match(ent, normalizedPattern) || + (recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern))) + ptr->push_back(iter->name); + } return ptr; - } + } - /* Gets called once for each of the ogre formats, *.program, - *.material etc. We ignore all these. + FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, + bool dirs = false) const + { + std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); + FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); + const Bsa::BSAFile::FileList &filelist = arc.getList(); - However, it's also called by MyGUI to find individual textures, - and we can't ignore these since many of the GUI textures are - located in BSAs. So instead we channel it through exists() and - set up a single-element result list if the file is found. - */ - FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, - bool dirs = false) const - { - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileInfoGatherer (this, ptr)); - return ptr; - } + for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();iter++) + { + std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name)); + if(Ogre::StringUtil::match(ent, normalizedPattern) || + (recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern))) + { + std::string::size_type pt = ent.rfind('/'); + if(pt == std::string::npos) + pt = 0; + + FileInfo fi; + fi.archive = const_cast(this); + fi.path = std::string(iter->name, pt); + fi.filename = std::string(iter->name + ((ent[pt]=='/') ? pt+1 : pt)); + fi.compressedSize = fi.uncompressedSize = iter->fileSize; + + ptr->push_back(fi); + } + } + + return ptr; + } }; // An archive factory for BSA archives @@ -445,7 +347,6 @@ static void insertDirFactory() } } -} namespace Bsa { From 3220330ce0e0bcaf7899ed1492563330f79f0e91 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Wed, 16 Jan 2013 04:19:16 +0100 Subject: [PATCH 0077/1483] fix spelling in comment --- apps/openmw/mwscript/userextensions.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/userextensions.hpp b/apps/openmw/mwscript/userextensions.hpp index 3642eb5f49..4bc3b46ec0 100644 --- a/apps/openmw/mwscript/userextensions.hpp +++ b/apps/openmw/mwscript/userextensions.hpp @@ -13,7 +13,7 @@ namespace Interpreter namespace MWScript { - /// \brief Temporaty script functionality limited to the console + /// \brief Temporary script functionality limited to the console namespace User { void registerExtensions (Compiler::Extensions& extensions); From df602553d10fa69ed4ab6a4902daaefed276749d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Jan 2013 09:13:36 +0100 Subject: [PATCH 0078/1483] Reworked MWRender::Water to be more OOP-ish and possibly allow other reflection types. --- apps/openmw/mwrender/water.cpp | 270 +++++++++++++++++++++------------ apps/openmw/mwrender/water.hpp | 77 ++++++++-- 2 files changed, 238 insertions(+), 109 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 04a1263672..27b9fc6793 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -24,12 +24,163 @@ using namespace Ogre; namespace MWRender { +CubeReflection::CubeReflection(Ogre::SceneManager* sceneManager) + : Reflection(sceneManager) +{ + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().createManual("CubeReflection", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_CUBE_MAP, + 512,512, 0, PF_R8G8B8, TU_RENDERTARGET); + + mCamera = mSceneMgr->createCamera ("CubeCamera"); + mCamera->setNearClipDistance (5); + mCamera->setFarClipDistance (1000); + + for (int face = 0; face < 6; ++face) + { + mRenderTargets[face] = texture->getBuffer (face)->getRenderTarget(); + mRenderTargets[face]->removeAllViewports (); + Viewport* vp = mRenderTargets[face]->addViewport (mCamera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setMaterialScheme ("water_reflection"); + mRenderTargets[face]->setAutoUpdated(false); + + /* + Vector3 lookAt(0,0,0), up(0,0,0), right(0,0,0); + switch(face) + { + case 0: lookAt.x =-1; up.y = 1; right.z = 1; break; // +X + case 1: lookAt.x = 1; up.y = 1; right.z =-1; break; // -X + case 2: lookAt.y =-1; up.z = 1; right.x = 1; break; // +Y + case 3: lookAt.y = 1; up.z =-1; right.x = 1; break; // -Y + case 4: lookAt.z = 1; up.y = 1; right.x =-1; break; // +Z + case 5: lookAt.z =-1; up.y = 1; right.x =-1; break; // -Z + } + Quaternion orient(right, up, lookAt); + mCamera->setOrientation(orient); + */ + } +} + +CubeReflection::~CubeReflection () +{ + Ogre::TextureManager::getSingleton ().remove("CubeReflection"); + mSceneMgr->destroyCamera (mCamera); +} + +void CubeReflection::update () +{ + mParentCamera->getParentSceneNode ()->needUpdate (); + mCamera->setPosition(mParentCamera->getDerivedPosition()); +} + +// -------------------------------------------------------------------------------------------------------------------------------- + +PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) + : Reflection(sceneManager) + , mSky(sky) +{ + mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); + mSceneMgr->addRenderQueueListener(this); + + mTexture = TextureManager::getSingleton().createManual("WaterReflection", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_A8R8G8B8, TU_RENDERTARGET); + + mRenderTarget = mTexture->getBuffer()->getRenderTarget(); + Viewport* vp = mRenderTarget->addViewport(mCamera); + vp->setOverlaysEnabled(false); + vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); + vp->setShadowsEnabled(false); + // use fallback techniques without shadows and without mrt + vp->setMaterialScheme("water_reflection"); + mRenderTarget->addListener(this); + mRenderTarget->setActive(true); + + sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName()); +} + +PlaneReflection::~PlaneReflection () +{ + mRenderTarget->removeListener (this); + mSceneMgr->destroyCamera (mCamera); + TextureManager::getSingleton ().remove("WaterReflection"); +} + +void PlaneReflection::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) +{ + // We don't want the sky to get clipped by custom near clip plane (the water plane) + if (queueGroupId < 20 && mRenderActive) + { + mCamera->disableCustomNearClipPlane(); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + } +} + +void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) +{ + if (queueGroupId < 20 && mRenderActive) + { + if (!mIsUnderwater) + mCamera->enableCustomNearClipPlane(mErrorPlane); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + } +} + +void PlaneReflection::preRenderTargetUpdate(const RenderTargetEvent& evt) +{ + mParentCamera->getParentSceneNode ()->needUpdate (); + mCamera->setOrientation(mParentCamera->getDerivedOrientation()); + mCamera->setPosition(mParentCamera->getDerivedPosition()); + mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); + mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); + mCamera->setAspectRatio(mParentCamera->getAspectRatio()); + mCamera->setFOVy(mParentCamera->getFOVy()); + mRenderActive = true; + + Vector3 pos = mParentCamera->getRealPosition(); + pos.y = (mWaterPlane).d*2 - pos.y; + mSky->setSkyPosition(pos); + mCamera->enableReflection(mWaterPlane); +} + +void PlaneReflection::postRenderTargetUpdate(const RenderTargetEvent& evt) +{ + mSky->resetSkyPosition(); + mCamera->disableReflection(); + mCamera->disableCustomNearClipPlane(); + mRenderActive = false; +} + +void PlaneReflection::setWaterPlane (Plane plane) +{ + mWaterPlane = plane; + mErrorPlane = Plane(plane.normal, mWaterPlane.d - 5); +} + +void PlaneReflection::setActive (bool active) +{ + mRenderTarget->setActive(active); +} + +void PlaneReflection::setViewportBackground(Ogre::ColourValue colour) +{ + mRenderTarget->getViewport (0)->setBackgroundColour (colour); +} + +void PlaneReflection::setVisibilityMask (int flags) +{ + mRenderTarget->getViewport (0)->setVisibilityMask (flags); +} + +// -------------------------------------------------------------------------------------------------------------------------------- + Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell) : - mCamera (camera), mSceneManager (camera->getSceneManager()), + mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), - mReflectionTarget(0), mActive(1), mToggled(1), - mReflectionRenderActive(false), mRendering(rend), - mWaterTimer(0.f) + mActive(1), mToggled(1), + mRendering(rend), + mWaterTimer(0.f), + mReflection(NULL) { mSky = rend->getSkyManager(); @@ -43,13 +194,11 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z); - mWater = mSceneManager->createEntity("water"); + mWater = mSceneMgr->createEntity("water"); mWater->setVisibilityFlags(RV_Water); mWater->setCastShadows(false); - mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); - - mReflectionCamera = mSceneManager->createCamera("ReflectionCamera"); + mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); if(!(cell->mData.mFlags & cell->Interior)) { @@ -72,8 +221,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel underwaterDome->setMaterialName("Underwater_Dome"); */ - mSceneManager->addRenderQueueListener(this); - assignTextures(); setHeight(mTop); @@ -142,12 +289,9 @@ Water::~Water() { MeshManager::getSingleton().remove("water"); - if (mReflectionTarget) - mReflectionTexture->getBuffer()->getRenderTarget()->removeListener(this); - mWaterNode->detachObject(mWater); - mSceneManager->destroyEntity(mWater); - mSceneManager->destroySceneNode(mWaterNode); + mSceneMgr->destroyEntity(mWater); + mSceneMgr->destroySceneNode(mWaterNode); } void Water::changeCell(const ESM::Cell* cell) @@ -166,8 +310,8 @@ void Water::setHeight(const float height) mWaterPlane = Plane(Vector3::UNIT_Y, height); - // small error due to reflection texture size & reflection distortion - mErrorPlane = Plane(Vector3::UNIT_Y, height - 5); + if (mReflection) + mReflection->setWaterPlane(mWaterPlane); mWaterNode->setPosition(0, height, 0); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); @@ -190,6 +334,9 @@ Water::updateUnderwater(bool underwater) mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID; + if (mReflection) + mReflection->setUnderwater (mIsUnderwater); + updateVisible(); } @@ -198,37 +345,6 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); } -void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) -{ - if (evt.source == mReflectionTarget) - { - mCamera->getParentSceneNode ()->needUpdate (); - mReflectionCamera->setOrientation(mCamera->getDerivedOrientation()); - mReflectionCamera->setPosition(mCamera->getDerivedPosition()); - mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance()); - mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); - mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); - mReflectionCamera->setFOVy(mCamera->getFOVy()); - mReflectionRenderActive = true; - - Vector3 pos = mCamera->getRealPosition(); - pos.y = mTop*2 - pos.y; - mSky->setSkyPosition(pos); - mReflectionCamera->enableReflection(mWaterPlane); - } -} - -void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) -{ - if (evt.source == mReflectionTarget) - { - mSky->resetSkyPosition(); - mReflectionCamera->disableReflection(); - mReflectionCamera->disableCustomNearClipPlane(); - mReflectionRenderActive = false; - } -} - void Water::assignTextures() { if (Settings::Manager::getBool("shader", "Water")) @@ -246,34 +362,16 @@ void Water::assignTextures() void Water::setViewportBackground(const ColourValue& bg) { - if (mReflectionTarget) - mReflectionTarget->getViewport(0)->setBackgroundColour(bg); + if (mReflection) + mReflection->setViewportBackground(bg); } void Water::updateVisible() { mWater->setVisible(mToggled && mActive); - if (mReflectionTarget) - mReflectionTarget->setActive(mToggled && mActive); -} - -void Water::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) -{ - // We don't want the sky to get clipped by custom near clip plane (the water plane) - if (queueGroupId < 20 && mReflectionRenderActive) + if (mReflection) { - mReflectionCamera->disableCustomNearClipPlane(); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); - } -} - -void Water::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) -{ - if (queueGroupId < 20 && mReflectionRenderActive) - { - if (!mIsUnderwater) - mReflectionCamera->enableCustomNearClipPlane(mErrorPlane); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); + mReflection->setActive(mToggled && mActive); } } @@ -293,10 +391,10 @@ void Water::update(float dt) void Water::applyRTT() { - if (mReflectionTarget) + if (mReflection) { - TextureManager::getSingleton().remove("WaterReflection"); - mReflectionTarget = 0; + delete mReflection; + mReflection = NULL; } // Create rendertarget for reflection @@ -304,23 +402,9 @@ void Water::applyRTT() if (Settings::Manager::getBool("shader", "Water")) { - mReflectionTexture = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_A8R8G8B8, TU_RENDERTARGET); - - RenderTarget* rtt = mReflectionTexture->getBuffer()->getRenderTarget(); - Viewport* vp = rtt->addViewport(mReflectionCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); - vp->setShadowsEnabled(false); - // use fallback techniques without shadows and without mrt - vp->setMaterialScheme("water_reflection"); - rtt->addListener(this); - rtt->setActive(true); - - mReflectionTarget = rtt; - - sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mReflectionTexture->getName()); - + mReflection = new PlaneReflection(mSceneMgr, mSky); + mReflection->setParentCamera (mCamera); + mReflection->setWaterPlane(mWaterPlane); mWater->setRenderQueueGroup(RQG_Water); } else @@ -336,10 +420,8 @@ void Water::applyVisibilityMask() + RV_Misc * Settings::Manager::getBool("reflect misc", "Water") + RV_Sky; - if (mReflectionTarget) - { - mReflectionTexture->getBuffer()->getRenderTarget()->getViewport(0)->setVisibilityMask(mVisibilityFlags); - } + if (mReflection) + mReflection->setVisibilityMask(mVisibilityFlags); } void Water::processChangedSettings(const Settings::CategorySettingVector& settings) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index f1e3d7a3be..de78542b72 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,15 +30,73 @@ namespace MWRender { class SkyManager; class RenderingManager; + class Reflection + { + public: + Reflection(Ogre::SceneManager* sceneManager) + : mSceneMgr(sceneManager) {} + + virtual void setWaterPlane (Ogre::Plane plane) {} + virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } + void setUnderwater(bool underwater) { mIsUnderwater = underwater; } + virtual void setActive (bool active) {} + virtual void setViewportBackground(Ogre::ColourValue colour) {} + virtual void update() {} + virtual void setVisibilityMask (int flags) {} + + protected: + Ogre::Camera* mCamera; + Ogre::Camera* mParentCamera; + Ogre::TexturePtr mTexture; + Ogre::SceneManager* mSceneMgr; + bool mIsUnderwater; + }; + + class CubeReflection : public Reflection + { + public: + CubeReflection(Ogre::SceneManager* sceneManager); + virtual ~CubeReflection(); + + virtual void update(); + protected: + Ogre::RenderTarget* mRenderTargets[6]; + }; + + class PlaneReflection : public Reflection, public Ogre::RenderQueueListener, public Ogre::RenderTargetListener + { + public: + PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky); + virtual ~PlaneReflection(); + + virtual void setWaterPlane (Ogre::Plane plane); + virtual void setActive (bool active); + virtual void setVisibilityMask (int flags); + + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + + void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); + void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); + + virtual void setViewportBackground(Ogre::ColourValue colour); + + protected: + Ogre::RenderTarget* mRenderTarget; + SkyManager* mSky; + Ogre::Plane mWaterPlane; + Ogre::Plane mErrorPlane; + bool mRenderActive; + }; + /// Water rendering class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener, public sh::MaterialInstanceListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; - Ogre::SceneManager *mSceneManager; + Ogre::SceneManager *mSceneMgr; Ogre::Plane mWaterPlane; - Ogre::Plane mErrorPlane; Ogre::SceneNode *mWaterNode; Ogre::Entity *mWater; @@ -52,17 +110,9 @@ namespace MWRender { float mWaterTimer; - bool mReflectionRenderActive; - Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); protected: - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - - void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); - void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); - void applyRTT(); void applyVisibilityMask(); @@ -75,14 +125,11 @@ namespace MWRender { Ogre::MaterialPtr mMaterial; - Ogre::Camera* mReflectionCamera; - - Ogre::TexturePtr mReflectionTexture; - Ogre::RenderTarget* mReflectionTarget; - bool mUnderwaterEffect; int mVisibilityFlags; + Reflection* mReflection; + public: Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); ~Water(); From 3c02e1ccc9f82a7ede31a0634a5688aec359216a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 08:22:38 -0800 Subject: [PATCH 0079/1483] Run physics right after updating the actors --- apps/openmw/engine.cpp | 6 +----- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +-- apps/openmw/mwmechanics/actors.cpp | 6 ++++-- apps/openmw/mwmechanics/actors.hpp | 3 +-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 ++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 3 +-- 6 files changed, 10 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e6296ab962..b1554fc750 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -96,13 +96,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWorld()->markCellAsUnchanged(); // update actors - std::vector > movement; - MWBase::Environment::get().getMechanicsManager()->update (movement, mEnvironment.getFrameDuration(), + MWBase::Environment::get().getMechanicsManager()->update(mEnvironment.getFrameDuration(), MWBase::Environment::get().getWindowManager()->isGuiMode()); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration()); - // update world MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode()); diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index a1023c9866..55eb729a4a 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -52,8 +52,7 @@ namespace MWBase ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - virtual void update (std::vector >& movement, - float duration, bool paused) = 0; + virtual void update (float duration, bool paused) = 0; ///< Update actor stats and store desired velocity vectors in \a movement /// /// \param paused In game type does not currently advance (this usually means some GUI diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4eae6e2137..485d7448ba 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -193,8 +193,7 @@ namespace MWMechanics } } - void Actors::update (std::vector >& movement, float duration, - bool paused) + void Actors::update (float duration, bool paused) { mDuration += duration; @@ -257,12 +256,15 @@ namespace MWMechanics } } + std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } + if (!paused) + MWBase::Environment::get().getWorld()->doPhysics (movement, duration); } void Actors::restoreDynamicStats() diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index f1e5ab437a..faf21a12fc 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -56,8 +56,7 @@ namespace MWMechanics void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. - void update (std::vector >& movement, - float duration, bool paused); + void update (float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement void updateActor (const MWWorld::Ptr& ptr, float duration); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index dae417d448..3b57c3485f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -201,8 +201,7 @@ namespace MWMechanics mWatched = ptr; } - void MechanicsManager::update (std::vector >& movement, - float duration, bool paused) + void MechanicsManager::update (float duration, bool paused) { if (!mWatched.isEmpty()) { @@ -298,7 +297,7 @@ namespace MWMechanics winMgr->configureSkills (majorSkills, minorSkills); } - mActors.update (movement, duration, paused); + mActors.update (duration, paused); } void MechanicsManager::restoreDynamicStats() diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index d3a97db361..0efe12f323 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -54,8 +54,7 @@ namespace MWMechanics ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - virtual void update (std::vector >& movement, - float duration, bool paused); + virtual void update (float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement /// /// \param paused In game type does not currently advance (this usually means some GUI From c1b32d6006adb35d989808e6eb2248cce431409f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 08:24:20 -0800 Subject: [PATCH 0080/1483] Remove outdated comments --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 -- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 55eb729a4a..401e360d7a 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -39,8 +39,6 @@ namespace MWBase virtual void addActor (const MWWorld::Ptr& ptr) = 0; ///< Register an actor for stats management - /// - /// \note Dead actors are ignored. virtual void removeActor (const MWWorld::Ptr& ptr) = 0; ///< Deregister an actor for stats management diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 0efe12f323..549807285e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -41,8 +41,6 @@ namespace MWMechanics virtual void addActor (const MWWorld::Ptr& ptr); ///< Register an actor for stats management - /// - /// \note Dead actors are ignored. virtual void removeActor (const MWWorld::Ptr& ptr); ///< Deregister an actor for stats management From 63e685ea39d30fc2892166841c7776553a0548d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 09:59:19 -0800 Subject: [PATCH 0081/1483] Add a method to get the Animation from a Ptr --- apps/openmw/mwbase/world.hpp | 4 ++++ apps/openmw/mwrender/actors.cpp | 8 ++++++++ apps/openmw/mwrender/actors.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 8 ++++++++ apps/openmw/mwrender/renderingmanager.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 4 ++++ 7 files changed, 34 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index b8557368d0..f846c51ba6 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -36,6 +36,7 @@ namespace ESM namespace MWRender { class ExternalRendering; + class Animation; } namespace MWWorld @@ -308,6 +309,9 @@ namespace MWBase /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; + /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void stopVideo() = 0; diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index c36248aafa..10b654834e 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -145,6 +145,14 @@ void Actors::update (float duration) iter->second->runAnimation(duration); } +Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) +{ + PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + return iter->second; + return NULL; +} + void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { Ogre::SceneNode *node; diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 53829000ca..92965a059c 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -54,6 +54,8 @@ namespace MWRender /// Updates containing cell for object rendering data void updateObjectCell(const MWWorld::Ptr &ptr); + + Animation* getAnimation(const MWWorld::Ptr &ptr); }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fdad152e61..d1f0b17aa5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -929,6 +929,14 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend rendering.setup (mRendering.getScene()); } +Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) +{ + Animation *anim = mActors.getAnimation(ptr); + // TODO: Check mObjects too. + return anim; +} + + void RenderingManager::playVideo(const std::string& name, bool allowSkipping) { mVideoPlayer->playVideo ("video/" + name, allowSkipping); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 68f2d79c37..1a7d213f31 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -46,6 +46,7 @@ namespace MWRender class ExternalRendering; class GlobalMap; class VideoPlayer; + class Animation; class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { @@ -196,6 +197,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setupExternalRendering (MWRender::ExternalRendering& rendering); + Animation* getAnimation(const MWWorld::Ptr &ptr); + void playVideo(const std::string& name, bool allowSkipping); void stopVideo(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f49b4bf9b5..b855bab8f0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1374,6 +1374,11 @@ namespace MWWorld } + MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) + { + return mRendering->getAnimation(ptr); + } + void World::playVideo (const std::string &name, bool allowSkipping) { mRendering->playVideo(name, allowSkipping); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7e89c1d871..f622144b20 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -37,6 +37,7 @@ namespace MWRender { class SkyManager; class CellRender; + class Animation; } namespace MWWorld @@ -352,6 +353,9 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); + /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping); virtual void stopVideo(); From b378bc92a06422c55290be5cb9dbac6f295b145a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 10:16:37 -0800 Subject: [PATCH 0082/1483] Store an animation object in the character controller --- apps/openmw/mwmechanics/actors.cpp | 5 +++-- apps/openmw/mwmechanics/character.hpp | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 485d7448ba..bd7a9cef2c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -165,11 +165,12 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else { - mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Dead))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 206f6e737f..8a09861177 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -3,6 +3,11 @@ #include "../mwworld/ptr.hpp" +namespace MWRender +{ + class Animation; +} + namespace MWMechanics { @@ -14,12 +19,13 @@ enum CharacterState { class CharacterController { MWWorld::Ptr mPtr; + MWRender::Animation *mAnimation; CharacterState mState; public: - CharacterController(const MWWorld::Ptr &ptr, CharacterState state) - : mPtr(ptr), mState(state) + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) + : mPtr(ptr), mAnimation(anim), mState(state) { } CharacterState getState() const From 3c487e601934b7422da4683fe5953d99298da7ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 10:45:18 -0800 Subject: [PATCH 0083/1483] Play an animation when changing states --- apps/openmw/mwmechanics/actors.cpp | 4 ---- apps/openmw/mwmechanics/character.cpp | 33 +++++++++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 8 ++----- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bd7a9cef2c..d9a3b6878e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,10 +169,7 @@ namespace MWMechanics if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else - { mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); - } } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -247,7 +244,6 @@ namespace MWMechanics } iter->second.setState(CharState_Dead); - MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 319c4fe9bd..6d5b928604 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,8 +19,41 @@ #include "character.hpp" +#include "../mwrender/animation.hpp" namespace MWMechanics { +CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) + : mPtr(ptr), mAnimation(anim), mState(state) +{ + if(!mAnimation) + return; + + switch(mState) + { + case CharState_Idle: + mAnimation->playGroup("idle", 1, 1); + break; + case CharState_Dead: + mAnimation->playGroup("death1", 1, 1); + break; + } +} + + +void CharacterController::setState(CharacterState state) +{ + mState = state; + switch(mState) + { + case CharState_Idle: + mAnimation->playGroup("idle", 1, 1); + break; + case CharState_Dead: + mAnimation->playGroup("death1", 1, 1); + break; + } +} + } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8a09861177..9bb3a1bfc3 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -24,15 +24,11 @@ class CharacterController CharacterState mState; public: - CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state) - { } + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); + void setState(CharacterState state); CharacterState getState() const { return mState; } - - void setState(CharacterState state) - { mState = state; } }; } From f46587c3836d040809cd6105b3a9ef3f5b45f7ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 11:01:08 -0800 Subject: [PATCH 0084/1483] Store an character controller in the animation --- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/animation.cpp | 6 ++++++ apps/openmw/mwrender/animation.hpp | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6d5b928604..21ebd255af 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,6 +30,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; + mAnimation->setController(this); switch(mState) { case CharState_Idle: diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b8016d0872..4f32de3647 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -95,6 +95,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +void Animation::setController(MWMechanics::CharacterController *controller) +{ + mController = controller; +} + + void Animation::updatePosition(float time) { mCurGroup.mAnimState->setTimePosition(time); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 859d2b9893..ed9e4f5855 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -5,6 +5,11 @@ #include "../mwworld/ptr.hpp" +namespace MWMechanics +{ + class CharacterController; +} + namespace MWRender { @@ -26,8 +31,9 @@ class Animation protected: MWWorld::Ptr mPtr; - Ogre::SceneNode* mInsert; + MWMechanics::CharacterController *mController; + Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; Ogre::Bone *mAccumRoot; @@ -56,6 +62,7 @@ public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); + void setController(MWMechanics::CharacterController *controller); void playGroup(std::string groupname, int mode, int loops); void skipAnim(); virtual void runAnimation(float timepassed); From 0a2f92f67901c06c80d9750cf40b197fd173a51d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 11:57:08 -0800 Subject: [PATCH 0085/1483] Keep track of the current text key in the animation --- apps/openmw/mwrender/animation.cpp | 27 +++++++++++++++++++++++++-- apps/openmw/mwrender/animation.hpp | 7 +++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4f32de3647..69bd01e2bb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -130,6 +130,11 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + + mCurGroup.mNext = mCurGroup.mStart; + while(mCurGroup.mNext->first < time) + mCurGroup.mNext++; + if(mNonAccumRoot) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); @@ -141,7 +146,8 @@ void Animation::resetPosition(float time) bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { - const NifOgre::TextKeyMap &textkeys = mTextKeys[groupname]; + times->mTextKeys = &mTextKeys[groupname]; + const NifOgre::TextKeyMap &textkeys = *times->mTextKeys; if(textkeys.size() == 0) return false; @@ -202,6 +208,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) std::cerr<< e.what() < 0) mNextGroup = times; @@ -211,7 +218,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(); - mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; + mTime = mCurGroup.mNext->first; mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); } @@ -230,6 +237,12 @@ void Animation::runAnimation(float timepassed) recheck: if(mTime >= mCurGroup.mLoopStop->first) { + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) + { + mCurGroup.mNext++; + } + if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; @@ -240,6 +253,11 @@ void Animation::runAnimation(float timepassed) } else if(mTime >= mCurGroup.mStop->first) { + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mCurGroup.mStop->first) + { + mCurGroup.mNext++; + } if(mNextGroup.mLoops > 0) { updatePosition(mCurGroup.mStop->first); @@ -254,6 +272,11 @@ void Animation::runAnimation(float timepassed) mTime = mCurGroup.mStop->first; } } + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mTime) + { + mCurGroup.mNext++; + } updatePosition(mTime); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ed9e4f5855..43cce0c028 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,16 +16,19 @@ namespace MWRender class Animation { struct GroupTimes { + NifOgre::TextKeyMap *mTextKeys; + NifOgre::TextKeyMap::const_iterator mStart; NifOgre::TextKeyMap::const_iterator mStop; NifOgre::TextKeyMap::const_iterator mLoopStart; NifOgre::TextKeyMap::const_iterator mLoopStop; + NifOgre::TextKeyMap::const_iterator mNext; + Ogre::AnimationState *mAnimState; size_t mLoops; - GroupTimes() - : mAnimState(NULL), mLoops(0) + GroupTimes() : mTextKeys(NULL), mAnimState(NULL), mLoops(0) { } }; From d2fc3c7b333f7dedd605b073dcd5a22eb853e3b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 13:09:21 -0800 Subject: [PATCH 0086/1483] Add a method to tell the character controller of new text keys --- apps/openmw/mwmechanics/character.cpp | 21 +++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 7 +++++++ apps/openmw/mwrender/animation.cpp | 9 +++++++++ 3 files changed, 37 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21ebd255af..6496ba9f27 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,7 @@ #include "../mwrender/animation.hpp" + namespace MWMechanics { @@ -42,6 +43,26 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } } +CharacterController::CharacterController(const CharacterController &rhs) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) +{ + if(!mAnimation) + return; + /* We've been copied. Update the animation with the new controller. */ + mAnimation->setController(this); +} + + +void CharacterController::markerEvent(const std::string &evt) +{ + std::string::size_type gp = evt.find(':'); + if(gp >= evt.length()-2) + { + std::cerr<< "Unexpected animation marker: \""<end() && mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } @@ -256,6 +261,8 @@ void Animation::runAnimation(float timepassed) while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first <= mCurGroup.mStop->first) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } if(mNextGroup.mLoops > 0) @@ -275,6 +282,8 @@ void Animation::runAnimation(float timepassed) while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first <= mTime) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } From 94b93227d32a9753447985a1fbc78af3c8c7230a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 14:37:32 -0800 Subject: [PATCH 0087/1483] Treat activators as actors for rendering and mechanics Kinda hacky, but it's the only way to get animated activators (flags, silt striders, etc) to work properly. --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwclass/activator.cpp | 9 +-- apps/openmw/mwmechanics/actors.cpp | 14 ++++- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/activatoranimation.cpp | 64 +++++++++++++++++++++ apps/openmw/mwrender/activatoranimation.hpp | 23 ++++++++ apps/openmw/mwrender/actors.cpp | 8 +++ apps/openmw/mwrender/actors.hpp | 3 +- apps/openmw/mwrender/animation.cpp | 3 + 9 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 apps/openmw/mwrender/activatoranimation.cpp create mode 100644 apps/openmw/mwrender/activatoranimation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 563c9e422a..ec7700beee 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -14,8 +14,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - renderingmanager debugging sky player animation npcanimation creatureanimation actors objects - renderinginterface localmap occlusionquery terrain terrainmaterial water shadows + renderingmanager debugging sky player animation npcanimation creatureanimation activatoranimation + actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows compositors characterpreview externalrendering globalmap videoplayer ) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 26d286aa14..2926272866 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -5,12 +5,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld//cellstore.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/physicssystem.hpp" -#include "../mwrender/objects.hpp" +#include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwgui/tooltips.hpp" @@ -21,9 +22,8 @@ namespace MWClass { const std::string model = getModel(ptr); if (!model.empty()) { - MWRender::Objects& objects = renderingInterface.getObjects(); - objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, model); + MWRender::Actors& actors = renderingInterface.getActors(); + actors.insertActivator(ptr); } } @@ -32,6 +32,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addObject(ptr); + MWBase::Environment::get().getMechanicsManager()->addActor(ptr); } std::string Activator::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a3b6878e..23272e6745 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,7 +166,9 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) + /* Kind of a hack. Activators need a character controller to manage an idle state. */ + if(ptr.getTypeName() == typeid(ESM::Activator).name() || + !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); @@ -203,6 +205,11 @@ namespace MWMechanics PtrControllerMap::iterator iter(mActors.begin()); while(iter != mActors.end()) { + if(iter->first.getTypeName() == typeid(ESM::Activator).name()) + { + iter++; + continue; + } if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) @@ -267,7 +274,10 @@ namespace MWMechanics void Actors::restoreDynamicStats() { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - calculateRestoration(iter->first, 3600); + { + if(iter->first.getTypeName() != typeid(ESM::Activator).name()) + calculateRestoration(iter->first, 3600); + } } int Actors::countDeaths (const std::string& id) const diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6496ba9f27..5bf468ffbf 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,7 @@ #include "../mwrender/animation.hpp" +#include "../mwworld/class.hpp" namespace MWMechanics { diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp new file mode 100644 index 0000000000..18ae318651 --- /dev/null +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -0,0 +1,64 @@ +#include "activatoranimation.hpp" + +#include +#include +#include + +#include "renderconst.hpp" + +#include "../mwbase/world.hpp" + +namespace MWRender +{ + +ActivatorAnimation::~ActivatorAnimation() +{ +} + +ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) + : Animation(ptr) +{ + MWWorld::LiveCellRef *ref = mPtr.get(); + + assert (ref->mBase != NULL); + if(!ref->mBase->mModel.empty()) + { + std::string mesh = "meshes\\" + ref->mBase->mModel; + + createEntityList(mPtr.getRefData().getBaseNode(), mesh); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) + { + Ogre::Entity *ent = mEntityList.mEntities[i]; + + bool transparent = false; + for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + { + Ogre::MaterialPtr mat = ent->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; + } + } + } + ent->setVisibilityFlags(RV_Misc); + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + } + } +} + +void ActivatorAnimation::runAnimation(float timepassed) +{ + // Placeholder + + Animation::runAnimation(timepassed); +} + +} diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp new file mode 100644 index 0000000000..f3d8d86c86 --- /dev/null +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -0,0 +1,23 @@ +#ifndef _GAME_RENDER_ACTIVATORANIMATION_H +#define _GAME_RENDER_ACTIVATORANIMATION_H + +#include "animation.hpp" + +namespace MWWorld +{ + class Ptr; +} + +namespace MWRender +{ + class ActivatorAnimation : public Animation + { + public: + ActivatorAnimation(const MWWorld::Ptr& ptr); + virtual ~ActivatorAnimation(); + + virtual void runAnimation(float timepassed); + }; +} + +#endif diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 10b654834e..d62e16fa21 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,6 +6,7 @@ #include "../mwworld/ptr.hpp" #include "animation.hpp" +#include "activatoranimation.hpp" #include "creatureanimation.hpp" #include "npcanimation.hpp" @@ -78,6 +79,13 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr) delete mAllActors[ptr]; mAllActors[ptr] = anim; } +void Actors::insertActivator (const MWWorld::Ptr& ptr) +{ + insertBegin(ptr); + ActivatorAnimation* anim = new ActivatorAnimation(ptr); + delete mAllActors[ptr]; + mAllActors[ptr] = anim; +} bool Actors::deleteObject (const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 92965a059c..4ef78c5779 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -31,8 +31,9 @@ namespace MWRender void setMwRoot(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr); - void insertCreature (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); + void insertCreature (const MWWorld::Ptr& ptr); + void insertActivator (const MWWorld::Ptr& ptr); bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5341ffd7a1..9784198457 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -200,6 +200,9 @@ void Animation::playGroup(std::string groupname, int mode, int loops) GroupTimes times; try { + if(!mEntityList.mSkelBase) + throw std::runtime_error("Attempting to animate an inanimate object"); + std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); times.mLoops = loops; From 3c32385e17f878e72a631d976cf3ae17fb8a6cef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 15:00:06 -0800 Subject: [PATCH 0088/1483] Avoid trying to animate things that don't have animations --- apps/openmw/mwmechanics/character.cpp | 7 +++++-- apps/openmw/mwrender/animation.cpp | 17 +++++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5bf468ffbf..47288b0c1e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,7 +29,7 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(!mAnimation) + if(!mAnimation || mAnimation->getAnimationCount() == 0) return; mAnimation->setController(this); @@ -47,7 +47,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) { - if(!mAnimation) + if(!mAnimation || mAnimation->getAnimationCount() == 0) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -68,6 +68,9 @@ void CharacterController::markerEvent(const std::string &evt) void CharacterController::setState(CharacterState state) { mState = state; + + if(!mAnimation || mAnimation->getAnimationCount() == 0) + return; switch(mState) { case CharState_Idle: diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9784198457..66d64f9d46 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,6 +98,23 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +int Animation::getAnimationCount() +{ + int num = 0; + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); + while(ai.hasMoreElements()) + { + num++; + ai.moveNext(); + } + } + return num; +} + + void Animation::setController(MWMechanics::CharacterController *controller) { mController = controller; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 43cce0c028..0e5c7e66ee 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -66,6 +66,8 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); + int getAnimationCount(); + void playGroup(std::string groupname, int mode, int loops); void skipAnim(); virtual void runAnimation(float timepassed); From 46728ab27ff387b46fd8b0893400218c8af10be2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 15:52:03 -0800 Subject: [PATCH 0089/1483] Handle "sound:" animation events --- apps/openmw/mwmechanics/character.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 47288b0c1e..6acd9a7cf9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,9 @@ #include "../mwrender/animation.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" + #include "../mwworld/class.hpp" namespace MWMechanics @@ -56,11 +59,10 @@ CharacterController::CharacterController(const CharacterController &rhs) void CharacterController::markerEvent(const std::string &evt) { - std::string::size_type gp = evt.find(':'); - if(gp >= evt.length()-2) + if(evt.compare(0, 6, "sound:") == 0) { - std::cerr<< "Unexpected animation marker: \""<playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); } } From 4c0e0fc279e833b5092caf3f7198dc6b50b20c7c Mon Sep 17 00:00:00 2001 From: pvdk Date: Thu, 17 Jan 2013 01:30:15 +0100 Subject: [PATCH 0090/1483] Modified license filename of the DejaVu font, more similar to the other one now --- Dejavu_lgc_font_license.txt => DejaVu Font License.txt | 0 credits.txt | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Dejavu_lgc_font_license.txt => DejaVu Font License.txt (100%) diff --git a/Dejavu_lgc_font_license.txt b/DejaVu Font License.txt similarity index 100% rename from Dejavu_lgc_font_license.txt rename to DejaVu Font License.txt diff --git a/credits.txt b/credits.txt index 878cbf9153..5d486c74e7 100644 --- a/credits.txt +++ b/credits.txt @@ -119,4 +119,4 @@ Thanks to Dongle, for his Daedric fontface, see Daedric Font License.txt for his license terms. Thanks to DejaVu team, -for their DejaVuLGCSansMono fontface, see Dejavu_lgc_font_license.txt for their license terms. +for their DejaVuLGCSansMono fontface, see DejaVu Font License.txt for their license terms. From 46fc61a4c19877a883f44d161fd95c31fc023015 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 16:31:09 -0800 Subject: [PATCH 0091/1483] Run animations from the character controller --- apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/character.cpp | 15 ++++++++++++--- apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/actors.cpp | 3 +-- apps/openmw/mwrender/player.cpp | 3 --- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 23272e6745..7205e7d544 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -263,6 +263,7 @@ namespace MWMechanics std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { + iter->second.update(duration); Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6acd9a7cf9..87ed8a9e6a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -32,7 +32,9 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(mAnimation && mAnimation->getAnimationCount() == 0) + mAnimation = NULL; + if(!mAnimation) return; mAnimation->setController(this); @@ -50,7 +52,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) { - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -67,11 +69,18 @@ void CharacterController::markerEvent(const std::string &evt) } +void CharacterController::update(float duration) +{ + if(mAnimation) + mAnimation->runAnimation(duration); +} + + void CharacterController::setState(CharacterState state) { mState = state; - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(!mAnimation) return; switch(mState) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c09cb8e421..3a59ae4bbd 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -33,6 +33,8 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); CharacterController(const CharacterController &rhs); + void update(float duration); + void setState(CharacterState state); CharacterState getState() const { return mState; } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index d62e16fa21..91395277be 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -149,8 +149,7 @@ void Actors::skipAnimation (const MWWorld::Ptr& ptr) } void Actors::update (float duration) { - for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++) - iter->second->runAnimation(duration); + // Nothing to do } Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 0e4c76b0ed..8f3e130395 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -129,9 +129,6 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - if (mAnimation) { - mAnimation->runAnimation(duration); - } mPlayerNode->setVisible( mVanity.enabled || mPreviewMode || !mFirstPersonView, false From 4feaa66897e55ff9ffc2a011bceed5fee1156799 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 17 Jan 2013 01:58:44 +0100 Subject: [PATCH 0092/1483] Do not open the dialogue window if no greeting is found --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f9d8c34596..535145a00b 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -122,15 +122,9 @@ namespace MWDialogue MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); mTalkedTo = creatureStats.hasTalkedToPlayer(); - creatureStats.talkedToPlayer(); mActorKnownTopics.clear(); - //initialise the GUI - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); - //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI updateTopics(); @@ -146,6 +140,13 @@ namespace MWDialogue { if (const ESM::DialInfo *info = filter.search (*it)) { + //initialise the GUI + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); + + creatureStats.talkedToPlayer(); + if (!info->mSound.empty()) { // TODO play sound From d2f5a886c731fe9d20ce176f81a5b20bb80c5077 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 17:53:18 -0800 Subject: [PATCH 0093/1483] Handle playgroup and skipanim through mwmechanics --- apps/openmw/mwbase/mechanicsmanager.hpp | 11 +++++++++++ apps/openmw/mwbase/world.hpp | 12 ------------ apps/openmw/mwmechanics/actors.cpp | 13 +++++++++++++ apps/openmw/mwmechanics/actors.hpp | 3 +++ apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++++ apps/openmw/mwmechanics/character.hpp | 3 +++ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 10 ++++++++++ apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 3 +++ apps/openmw/mwrender/actors.cpp | 12 ------------ apps/openmw/mwrender/actors.hpp | 12 ------------ apps/openmw/mwrender/renderingmanager.cpp | 11 ----------- apps/openmw/mwrender/renderingmanager.hpp | 12 ------------ apps/openmw/mwscript/animationextensions.cpp | 8 ++++---- apps/openmw/mwworld/worldimp.cpp | 11 ----------- apps/openmw/mwworld/worldimp.hpp | 12 ------------ 15 files changed, 61 insertions(+), 86 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 401e360d7a..f7bbd6a9f9 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -95,6 +95,17 @@ namespace MWBase virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; ///< Perform a persuasion action on NPC + + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + ///< Run animation for a MW-reference. Calls to this function for references that are currently not + /// in the scene should be ignored. + /// + /// \param mode 0 normal, 1 immediate start, 2 immediate loop + /// \param count How many times the animation should be run + + virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; + ///< Skip the animation for the given MW-reference for one frame. Calls to this function for + /// references that are currently not in the scene should be ignored. }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f846c51ba6..c75e96a6e3 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -260,18 +260,6 @@ namespace MWBase ///< Create a new recrod (of type npc) in the ESM store. /// \return pointer to created record - virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number = 1) = 0; - ///< Run animation for a MW-reference. Calls to this function for references that are - /// currently not in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - virtual void skipAnimation (const MWWorld::Ptr& ptr) = 0; - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - virtual void update (float duration, bool paused) = 0; virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7205e7d544..749fb26654 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -288,4 +288,17 @@ namespace MWMechanics return iter->second; return 0; } + + void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + iter->second.playGroup(groupName, mode, number); + } + void Actors::skipAnimation(const MWWorld::Ptr& ptr) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + iter->second.skipAnim(); + } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index faf21a12fc..6fed9eff73 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -68,6 +68,9 @@ namespace MWMechanics int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); }; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 87ed8a9e6a..21697f996c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -76,6 +76,20 @@ void CharacterController::update(float duration) } +void CharacterController::playGroup(const std::string &groupname, int mode, int count) +{ + // set mState = CharState_Idle? + if(mAnimation) + mAnimation->playGroup(groupname, mode, count); +} + +void CharacterController::skipAnim() +{ + if(mAnimation) + mAnimation->skipAnim(); +} + + void CharacterController::setState(CharacterState state) { mState = state; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 3a59ae4bbd..24e129e386 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -35,6 +35,9 @@ public: void update(float duration); + void playGroup(const std::string &groupname, int mode, int count); + void skipAnim(); + void setState(CharacterState state); CharacterState getState() const { return mState; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3b57c3485f..84145eb082 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -628,4 +628,14 @@ namespace MWMechanics permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; } } + + void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + { + mActors.playAnimationGroup(ptr, groupName, mode, number); + } + void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) + { + mActors.skipAnimation(ptr); + } + } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 549807285e..c2bbd96cfe 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -89,6 +89,9 @@ namespace MWMechanics float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); void toLower(std::string npcFaction); ///< Perform a persuasion action on NPC + + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + virtual void skipAnimation(const MWWorld::Ptr& ptr); }; } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 91395277be..12ebdab614 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -135,18 +135,6 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) } } -void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) -{ - PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); - if(iter != mAllActors.end()) - iter->second->playGroup(groupName, mode, number); -} -void Actors::skipAnimation (const MWWorld::Ptr& ptr) -{ - PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); - if(iter != mAllActors.end()) - iter->second->skipAnim(); -} void Actors::update (float duration) { // Nothing to do diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 4ef78c5779..fc9fa4fbba 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -39,18 +39,6 @@ namespace MWRender void removeCell(MWWorld::CellStore* store); - void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are currently not - /// in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - void update (float duration); /// Updates containing cell for object rendering data diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d1f0b17aa5..ea898e1fa1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -580,17 +580,6 @@ void RenderingManager::toggleLight() setAmbientMode(); } -void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number) -{ - mActors.playAnimationGroup(ptr, groupName, mode, number); -} - -void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr) -{ - mActors.skipAnimation(ptr); -} - void RenderingManager::setSunColour(const Ogre::ColourValue& colour) { if (!mSunEnabled) return; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1a7d213f31..b6c33f9c01 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -167,18 +167,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList /// configure fog manually void configureFog(const float density, const Ogre::ColourValue& colour); - void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are currently not - /// in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); ///< transform the specified bounding box (in world coordinates) into screen coordinates. /// @return packed vector4 (min_x, min_y, max_x, max_y) diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 6f9253e5db..fc52e5e167 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -9,7 +9,7 @@ #include #include -#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -27,7 +27,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWBase::Environment::get().getWorld()->skipAnimation (ptr); + MWBase::Environment::get().getMechanicsManager()->skipAnimation (ptr); } }; @@ -54,7 +54,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, 1); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, 1); } }; @@ -87,7 +87,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, loops); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, loops); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b855bab8f0..de4cb84ef5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -903,17 +903,6 @@ namespace MWWorld return ret; } - void World::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number) - { - mRendering->playAnimationGroup (ptr, groupName, mode, number); - } - - void World::skipAnimation (const MWWorld::Ptr& ptr) - { - mRendering->skipAnimation (ptr); - } - void World::update (float duration, bool paused) { mWorldScene->update (duration, paused); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f622144b20..67185833f0 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -291,18 +291,6 @@ namespace MWWorld /// \return pointer to created record - virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are - /// currently not in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - virtual void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - virtual void update (float duration, bool paused); virtual bool placeObject (const Ptr& object, float cursorX, float cursorY); From daad8d985963786242782bd72c7527aa02059006 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 18:03:39 -0800 Subject: [PATCH 0094/1483] Don't update the character controller while paused --- apps/openmw/mwmechanics/actors.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 749fb26654..101a0a51d5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -260,16 +260,18 @@ namespace MWMechanics } } - std::vector > movement; - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + if(!paused) { - iter->second.update(duration); - Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - if(vector!=Ogre::Vector3::ZERO) - movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); - } - if (!paused) + std::vector > movement; + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + iter->second.update(duration); + Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + if(vector!=Ogre::Vector3::ZERO) + movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); + } MWBase::Environment::get().getWorld()->doPhysics (movement, duration); + } } void Actors::restoreDynamicStats() From 685f21956001e5eeb64b5b200748ec89f6e195af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 18:56:13 -0800 Subject: [PATCH 0095/1483] Return a movement vector from the character controller update --- apps/openmw/mwmechanics/actors.cpp | 3 +-- apps/openmw/mwmechanics/character.cpp | 3 ++- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 101a0a51d5..35bca441ae 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -265,8 +265,7 @@ namespace MWMechanics std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - iter->second.update(duration); - Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + Ogre::Vector3 vector = iter->second.update(duration); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21697f996c..8e5ac0a4ac 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -69,10 +69,11 @@ void CharacterController::markerEvent(const std::string &evt) } -void CharacterController::update(float duration) +Ogre::Vector3 CharacterController::update(float duration) { if(mAnimation) mAnimation->runAnimation(duration); + return MWWorld::Class::get(mPtr).getMovementVector(mPtr); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 24e129e386..83f42887d6 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -33,7 +33,7 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); CharacterController(const CharacterController &rhs); - void update(float duration); + Ogre::Vector3 update(float duration); void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); From 4dd01b81c6cd63aa0153f2a6efb742e3b0c06a56 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 20:14:49 -0800 Subject: [PATCH 0096/1483] Update mTime when updating or reseting the animation, and refactor the animation loop --- apps/openmw/mwrender/animation.cpp | 90 +++++++++++++----------------- 1 file changed, 38 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 66d64f9d46..30532b624e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -124,6 +124,8 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + mTime = time; + if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the @@ -150,9 +152,10 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + mTime = time; mCurGroup.mNext = mCurGroup.mStart; - while(mCurGroup.mNext->first < time) + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first < time) mCurGroup.mNext++; if(mNonAccumRoot) @@ -233,7 +236,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) } times.mNext = ((mode==2) ? times.mLoopStart : times.mStart); - if(mode == 0 && mCurGroup.mLoops > 0) + if(mode == 0 && mCurGroup.mAnimState) mNextGroup = times; else { @@ -241,9 +244,8 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(); - mTime = mCurGroup.mNext->first; mCurGroup.mAnimState->setEnabled(true); - resetPosition(mTime); + resetPosition(mCurGroup.mNext->first); } } @@ -254,62 +256,46 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mCurGroup.mAnimState && !mSkipFrame) - { - mTime += timepassed; - recheck: - if(mTime >= mCurGroup.mLoopStop->first) - { - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) - { - if(mController) - mController->markerEvent(mCurGroup.mNext->second); - mCurGroup.mNext++; - } + if(mSkipFrame) + timepassed = 0.0f; + mSkipFrame = false; - if(mCurGroup.mLoops > 1) - { - mCurGroup.mLoops--; - updatePosition(mCurGroup.mLoopStop->first); - mTime = mTime - mCurGroup.mLoopStop->first + mCurGroup.mLoopStart->first; - resetPosition(mCurGroup.mLoopStart->first); - goto recheck; - } - else if(mTime >= mCurGroup.mStop->first) - { - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mCurGroup.mStop->first) - { - if(mController) - mController->markerEvent(mCurGroup.mNext->second); - mCurGroup.mNext++; - } - if(mNextGroup.mLoops > 0) - { - updatePosition(mCurGroup.mStop->first); - mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; - mCurGroup.mAnimState->setEnabled(false); - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mStart->first); - goto recheck; - } - mTime = mCurGroup.mStop->first; - } - } - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mTime) + while(mCurGroup.mAnimState && timepassed > 0.0f) + { + float targetTime = mTime + timepassed; + if(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= targetTime) { + updatePosition(mCurGroup.mNext->first); + timepassed = targetTime - mTime; + if(mController) mController->markerEvent(mCurGroup.mNext->second); + if(mCurGroup.mNext == mCurGroup.mLoopStop && mCurGroup.mLoops > 1) + { + mCurGroup.mLoops--; + resetPosition(mCurGroup.mLoopStart->first); + continue; + } + else if(mCurGroup.mNext == mCurGroup.mStop) + { + if(!mNextGroup.mAnimState) + break; + + mCurGroup.mAnimState->setEnabled(false); + mCurGroup = mNextGroup; + mNextGroup = GroupTimes(); + mCurGroup.mAnimState->setEnabled(true); + resetPosition(mCurGroup.mStart->first); + continue; + } mCurGroup.mNext++; + continue; } - updatePosition(mTime); + updatePosition(targetTime); + timepassed = targetTime - mTime; } - mSkipFrame = false; } } From afbc9f3e41cad0dcc1c29e8ecc36af7facc27c4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 20:44:37 -0800 Subject: [PATCH 0097/1483] Keep track of the animation group currently playing --- apps/openmw/mwmechanics/character.cpp | 12 ++++++++---- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8e5ac0a4ac..8786c42e12 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,10 +41,12 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim switch(mState) { case CharState_Idle: - mAnimation->playGroup("idle", 1, 1); + mCurrentGroup = "idle"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; case CharState_Dead: - mAnimation->playGroup("death1", 1, 1); + mCurrentGroup = "death1"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; } } @@ -100,10 +102,12 @@ void CharacterController::setState(CharacterState state) switch(mState) { case CharState_Idle: - mAnimation->playGroup("idle", 1, 1); + mCurrentGroup = "idle"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; case CharState_Dead: - mAnimation->playGroup("death1", 1, 1); + mCurrentGroup = "death1"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 83f42887d6..9070cbe29c 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,6 +21,7 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; + std::string mCurrentGroup; CharacterState mState; protected: From 852aa214cc6562c6f259277fa350f99be8167906 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:16:22 -0800 Subject: [PATCH 0098/1483] Store the available animation names in the character controller --- apps/openmw/mwmechanics/character.cpp | 16 ++++++++++------ apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/animation.cpp | 11 ++++------- apps/openmw/mwrender/animation.hpp | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8786c42e12..c347312c24 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -32,10 +32,13 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(mAnimation && mAnimation->getAnimationCount() == 0) + if(mAnimation) + mAnimNames = mAnimation->getAnimationNames(); + if(mAnimNames.size() == 0) + { mAnimation = NULL; - if(!mAnimation) return; + } mAnimation->setController(this); switch(mState) @@ -52,9 +55,10 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) + , mState(rhs.mState) { - if(!mAnimation) + if(mAnimNames.size() == 0) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -82,7 +86,7 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { // set mState = CharState_Idle? - if(mAnimation) + if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) mAnimation->playGroup(groupname, mode, count); } @@ -97,7 +101,7 @@ void CharacterController::setState(CharacterState state) { mState = state; - if(!mAnimation) + if(mAnimNames.size() == 0) return; switch(mState) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9070cbe29c..c29c39acdf 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,6 +21,8 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; + std::vector mAnimNames; + std::string mCurrentGroup; CharacterState mState; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30532b624e..1d628aefaa 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,20 +98,17 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } -int Animation::getAnimationCount() +std::vector Animation::getAnimationNames() { - int num = 0; + std::vector anims; if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); while(ai.hasMoreElements()) - { - num++; - ai.moveNext(); - } + anims.push_back(ai.getNext()->getAnimationName()); } - return num; + return anims; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0e5c7e66ee..3afe32a4b2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -66,7 +66,7 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); - int getAnimationCount(); + std::vector getAnimationNames(); void playGroup(std::string groupname, int mode, int loops); void skipAnim(); From 7ee389f3b2006bb05aee871e5774c32d64a65b6f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:25:50 -0800 Subject: [PATCH 0099/1483] Handle animation skipping in the character controller --- apps/openmw/mwmechanics/character.cpp | 10 +++++----- apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwrender/animation.cpp | 10 ---------- apps/openmw/mwrender/animation.hpp | 3 --- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c347312c24..547d9e0a50 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,7 +30,7 @@ namespace MWMechanics { CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state) + : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -56,7 +56,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mState(rhs.mState) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -77,8 +77,9 @@ void CharacterController::markerEvent(const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { - if(mAnimation) + if(mAnimation && !mSkipAnim) mAnimation->runAnimation(duration); + mSkipAnim = false; return MWWorld::Class::get(mPtr).getMovementVector(mPtr); } @@ -92,8 +93,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int void CharacterController::skipAnim() { - if(mAnimation) - mAnimation->skipAnim(); + mSkipAnim = true; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c29c39acdf..202e105784 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -25,6 +25,7 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; + bool mSkipAnim; protected: /* Called by the animation whenever a new text key is reached. */ diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1d628aefaa..c0b6a6e1cc 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -24,7 +24,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mTime(0.0f) - , mSkipFrame(false) { } @@ -246,17 +245,8 @@ void Animation::playGroup(std::string groupname, int mode, int loops) } } -void Animation::skipAnim() -{ - mSkipFrame = true; -} - void Animation::runAnimation(float timepassed) { - if(mSkipFrame) - timepassed = 0.0f; - mSkipFrame = false; - while(mCurGroup.mAnimState && timepassed > 0.0f) { float targetTime = mTime + timepassed; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3afe32a4b2..5dbe7b510a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -48,8 +48,6 @@ protected: GroupTimes mCurGroup; GroupTimes mNextGroup; - bool mSkipFrame; - /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ void updatePosition(float time); @@ -69,7 +67,6 @@ public: std::vector getAnimationNames(); void playGroup(std::string groupname, int mode, int loops); - void skipAnim(); virtual void runAnimation(float timepassed); }; From 82d549e22fc1e97794c31892172263fedc792c69 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:39:14 -0800 Subject: [PATCH 0100/1483] Don't update the animation if time is the same --- apps/openmw/mwrender/animation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0b6a6e1cc..d10accab77 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -119,6 +119,8 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { + if(time == mTime) + return; mCurGroup.mAnimState->setTimePosition(time); mTime = time; From da4f17859e12016cf62371ae87730c7f32b20e50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 10:16:36 -0800 Subject: [PATCH 0101/1483] Recognize soundgen animation markers --- apps/openmw/mwmechanics/character.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 547d9e0a50..7e5f15a9f1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -67,10 +67,17 @@ CharacterController::CharacterController(const CharacterController &rhs) void CharacterController::markerEvent(const std::string &evt) { - if(evt.compare(0, 6, "sound:") == 0) + if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + return; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + return; } } From 47c157303ac64e2fc1df34b1f87a4fe3fff28192 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 11:03:58 -0800 Subject: [PATCH 0102/1483] Filter events that do not belong to the current group --- apps/openmw/mwmechanics/character.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7e5f15a9f1..4385d0b9df 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -56,7 +56,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -79,6 +79,12 @@ void CharacterController::markerEvent(const std::string &evt) // to this actor type return; } + if(evt.length() <= mCurrentGroup.length()+2 || evt.compare(0, mCurrentGroup.length(), mCurrentGroup) != 0 || + evt.compare(mCurrentGroup.length(), 2, ": ") != 0) + { + std::cerr<< "Event \""< Date: Thu, 17 Jan 2013 13:18:40 -0800 Subject: [PATCH 0103/1483] Handle the animation queue in mwmechanics --- apps/openmw/mwmechanics/character.cpp | 55 ++++++++-- apps/openmw/mwmechanics/character.hpp | 3 + apps/openmw/mwrender/animation.cpp | 123 ++++++---------------- apps/openmw/mwrender/animation.hpp | 26 +---- apps/openmw/mwrender/characterpreview.cpp | 2 +- 5 files changed, 91 insertions(+), 118 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4385d0b9df..9fa2c74bea 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -45,18 +45,19 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim { case CharState_Idle: mCurrentGroup = "idle"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "stop"); break; } } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -79,12 +80,33 @@ void CharacterController::markerEvent(const std::string &evt) // to this actor type return; } - if(evt.length() <= mCurrentGroup.length()+2 || evt.compare(0, mCurrentGroup.length(), mCurrentGroup) != 0 || - evt.compare(mCurrentGroup.length(), 2, ": ") != 0) + std::string::size_type ms = mCurrentGroup.length()+2; + if(evt.length() <= ms || evt.compare(0, ms-2, mCurrentGroup) != 0 || evt.compare(ms-2, 2, ": ") != 0) { std::cerr<< "Event \""<= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start"); + } + } + else if(mAnimQueue.size() > 0) + { + if(evt.compare(ms, evt.length()-ms, "stop") == 0) + { + mAnimQueue.pop_front(); + if(mAnimQueue.size() > 0) + { + mCurrentGroup = mAnimQueue.front(); + mAnimation->play(mCurrentGroup, "start"); + } + } + } } @@ -101,7 +123,23 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int { // set mState = CharState_Idle? if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) - mAnimation->playGroup(groupname, mode, count); + { + count = std::max(count, 1); + if(mode != 0 || mAnimQueue.size() == 0) + { + mAnimQueue.clear(); + while(count-- > 0) + mAnimQueue.push_back(groupname); + mCurrentGroup = groupname; + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); + } + else if(mode == 0) + { + mAnimQueue.resize(1); + while(count-- > 0) + mAnimQueue.push_back(groupname); + } + } } void CharacterController::skipAnim() @@ -116,15 +154,16 @@ void CharacterController::setState(CharacterState state) if(mAnimNames.size() == 0) return; + mAnimQueue.clear(); switch(mState) { case CharState_Idle: mCurrentGroup = "idle"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 202e105784..992cb8f1fe 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -23,6 +23,9 @@ class CharacterController std::vector mAnimNames; + typedef std::deque AnimationQueue; + AnimationQueue mAnimQueue; + std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d10accab77..4d9ee108c9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,6 +23,8 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mStartPosition(0.0f) , mLastPosition(0.0f) + , mCurrentKeys(NULL) + , mAnimState(NULL) , mTime(0.0f) { } @@ -121,14 +123,14 @@ void Animation::updatePosition(float time) { if(time == mTime) return; - mCurGroup.mAnimState->setTimePosition(time); + mAnimState->setTimePosition(time); mTime = time; if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; /* Translate the accumulation root back to compensate for the move. */ @@ -149,136 +151,81 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { - mCurGroup.mAnimState->setTimePosition(time); + mAnimState->setTimePosition(time); mTime = time; - mCurGroup.mNext = mCurGroup.mStart; - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first < time) - mCurGroup.mNext++; + mNextKey = mCurrentKeys->begin(); + while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) + mNextKey++; if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } } -bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) +float Animation::findStart(const std::string &groupname, const std::string &start) { - times->mTextKeys = &mTextKeys[groupname]; - const NifOgre::TextKeyMap &textkeys = *times->mTextKeys; - if(textkeys.size() == 0) - return false; + mNextKey = mCurrentKeys->end(); + if(mCurrentKeys->size() == 0) + return 0.0f; if(groupname == "all") { - times->mStart = times->mLoopStart = textkeys.begin(); - times->mLoopStop = times->mStop = textkeys.end(); - times->mLoopStop--; times->mStop--; - return true; + mNextKey = mCurrentKeys->begin(); + return 0.0f; } - 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"; - - times->mStart = times->mLoopStart = - times->mStop = times->mLoopStop = textkeys.end(); - + std::string startmarker = groupname+": "+start; NifOgre::TextKeyMap::const_iterator iter; - for(iter = textkeys.begin();iter != textkeys.end();iter++) + for(iter = mCurrentKeys->begin();iter != mCurrentKeys->end();iter++) { - if(start == iter->second) - { - times->mStart = iter; - times->mLoopStart = iter; - } - else if(startloop == iter->second) - times->mLoopStart = iter; - else if(stoploop == iter->second) - times->mLoopStop = iter; - else if(stop == iter->second) - { - times->mStop = iter; - if(times->mLoopStop == textkeys.end()) - times->mLoopStop = iter; - return (times->mStart != textkeys.end()); - } + if(iter->second == startmarker) + return iter->first; } - - return false; + return 0.0f; } -void Animation::playGroup(std::string groupname, int mode, int loops) +void Animation::play(const std::string &groupname, const std::string &start) { - GroupTimes times; - + float time = 0.0f; try { if(!mEntityList.mSkelBase) throw std::runtime_error("Attempting to animate an inanimate object"); - std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); - times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - times.mLoops = loops; + if(mAnimState) + mAnimState->setEnabled(false); + mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); + mCurrentKeys = &mTextKeys[groupname]; + mAnimState->setEnabled(true); - if(!findGroupTimes(groupname, ×)) - throw std::runtime_error("Failed to find animation group "+groupname); + time = findStart(groupname, start); } catch(std::exception &e) { std::cerr<< e.what() <setEnabled(false); - mCurGroup = times; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mNext->first); - } + resetPosition(time); } void Animation::runAnimation(float timepassed) { - while(mCurGroup.mAnimState && timepassed > 0.0f) + while(mAnimState && timepassed > 0.0f) { float targetTime = mTime + timepassed; - if(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= targetTime) + if(mNextKey != mCurrentKeys->end() && mNextKey->first <= targetTime) { - updatePosition(mCurGroup.mNext->first); + const std::string &evt = mNextKey->second; + updatePosition(mNextKey->first); + mNextKey++; timepassed = targetTime - mTime; if(mController) - mController->markerEvent(mCurGroup.mNext->second); - if(mCurGroup.mNext == mCurGroup.mLoopStop && mCurGroup.mLoops > 1) - { - mCurGroup.mLoops--; - resetPosition(mCurGroup.mLoopStart->first); - continue; - } - else if(mCurGroup.mNext == mCurGroup.mStop) - { - if(!mNextGroup.mAnimState) - break; - - mCurGroup.mAnimState->setEnabled(false); - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mStart->first); - continue; - } - mCurGroup.mNext++; + mController->markerEvent(evt); continue; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5dbe7b510a..722eccc30f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -15,23 +15,6 @@ namespace MWRender class Animation { - struct GroupTimes { - NifOgre::TextKeyMap *mTextKeys; - - NifOgre::TextKeyMap::const_iterator mStart; - NifOgre::TextKeyMap::const_iterator mStop; - NifOgre::TextKeyMap::const_iterator mLoopStart; - NifOgre::TextKeyMap::const_iterator mLoopStop; - - NifOgre::TextKeyMap::const_iterator mNext; - - Ogre::AnimationState *mAnimState; - size_t mLoops; - - GroupTimes() : mTextKeys(NULL), mAnimState(NULL), mLoops(0) - { } - }; - protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; @@ -44,9 +27,10 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + NifOgre::TextKeyMap *mCurrentKeys; + NifOgre::TextKeyMap::const_iterator mNextKey; + Ogre::AnimationState *mAnimState; float mTime; - GroupTimes mCurGroup; - GroupTimes mNextGroup; /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ @@ -55,7 +39,7 @@ protected: * object. */ void resetPosition(float time); - bool findGroupTimes(const std::string &groupname, GroupTimes *times); + float findStart(const std::string &groupname, const std::string &start); void createEntityList(Ogre::SceneNode *node, const std::string &model); @@ -66,7 +50,7 @@ public: void setController(MWMechanics::CharacterController *controller); std::vector getAnimationNames(); - void playGroup(std::string groupname, int mode, int loops); + void play(const std::string &groupname, const std::string &start); virtual void runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index eb9954df65..cbee9c8659 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -144,7 +144,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->playGroup ("inventoryhandtohand", 0, 1); + mAnimation->play("inventoryhandtohand", "start"); } // -------------------------------------------------------------------------------------------------- From fc0f9e215909e15b5a09eb7edafdda4ce9dceada Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 14:49:42 -0800 Subject: [PATCH 0104/1483] The animation state tracks the animation time for us --- apps/openmw/mwrender/animation.cpp | 28 +++++++++++----------------- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4d9ee108c9..18aa982151 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -25,7 +25,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) - , mTime(0.0f) { } @@ -121,10 +120,7 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { - if(time == mTime) - return; mAnimState->setTimePosition(time); - mTime = time; if(mNonAccumRoot) { @@ -152,7 +148,6 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mAnimState->setTimePosition(time); - mTime = time; mNextKey = mCurrentKeys->begin(); while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) @@ -216,21 +211,20 @@ void Animation::runAnimation(float timepassed) { while(mAnimState && timepassed > 0.0f) { - float targetTime = mTime + timepassed; - if(mNextKey != mCurrentKeys->end() && mNextKey->first <= targetTime) + float targetTime = mAnimState->getTimePosition() + timepassed; + if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - const std::string &evt = mNextKey->second; - updatePosition(mNextKey->first); - mNextKey++; - timepassed = targetTime - mTime; - - if(mController) - mController->markerEvent(evt); - continue; + updatePosition(targetTime); + break; } - updatePosition(targetTime); - timepassed = targetTime - mTime; + const std::string &evt = mNextKey->second; + updatePosition(mNextKey->first); + timepassed = targetTime - mNextKey->first; + mNextKey++; + + if(mController) + mController->markerEvent(evt); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 722eccc30f..726d0cf388 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -30,7 +30,6 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; - float mTime; /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ From fef6284f15ebf7cafcfed1e3bb7e4a3727cddafe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 15:47:25 -0800 Subject: [PATCH 0105/1483] Only reset the animation time if a new state was set --- apps/openmw/mwrender/animation.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 18aa982151..1a464f5d84 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -187,24 +187,22 @@ float Animation::findStart(const std::string &groupname, const std::string &star void Animation::play(const std::string &groupname, const std::string &start) { - float time = 0.0f; try { if(!mEntityList.mSkelBase) throw std::runtime_error("Attempting to animate an inanimate object"); + Ogre::AnimationState *newstate = mEntityList.mSkelBase->getAnimationState(groupname); if(mAnimState) mAnimState->setEnabled(false); - mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mCurrentKeys = &mTextKeys[groupname]; + mAnimState = newstate; mAnimState->setEnabled(true); + mCurrentKeys = &mTextKeys[groupname]; - time = findStart(groupname, start); + resetPosition(findStart(groupname, start)); } catch(std::exception &e) { std::cerr<< e.what() < Date: Thu, 17 Jan 2013 15:48:09 -0800 Subject: [PATCH 0106/1483] Fix player rendering --- apps/openmw/mwrender/player.hpp | 4 +++- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 29a68ca693..e24f44d68a 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -95,7 +95,9 @@ namespace MWRender /// Restore default camera distance for current mode. void setCameraDistance(); - void setAnimation(MWRender::NpcAnimation *anim); + void setAnimation(NpcAnimation *anim); + NpcAnimation *getAnimation() const + { return mAnimation; } void setHeight(float height); float getHeight(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ea898e1fa1..082b561ef5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -921,7 +921,7 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors.getAnimation(ptr); - // TODO: Check mObjects too. + if(!anim) anim = mPlayer->getAnimation(); return anim; } From 8fa1b56efcbfc9869c9b22d14f0c1bfb72853de4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 16:34:26 -0800 Subject: [PATCH 0107/1483] Loop the current animation if there's nothing more queued --- apps/openmw/mwmechanics/character.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9fa2c74bea..a42771e0b2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -107,6 +107,11 @@ void CharacterController::markerEvent(const std::string &evt) } } } + else + { + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + mAnimation->play(mCurrentGroup, "loop start"); + } } @@ -130,6 +135,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); while(count-- > 0) mAnimQueue.push_back(groupname); + mAnimQueue.push_back("idle"); mCurrentGroup = groupname; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -138,6 +144,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.resize(1); while(count-- > 0) mAnimQueue.push_back(groupname); + mAnimQueue.push_back("idle"); } } } From 8720433fa9e171c1776db6845f93ad4c4986256b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 17:38:05 -0800 Subject: [PATCH 0108/1483] Do not automatically loop animations There are 0 length idle animations that break this --- apps/openmw/mwmechanics/character.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a42771e0b2..0b8eff7331 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -107,11 +107,6 @@ void CharacterController::markerEvent(const std::string &evt) } } } - else - { - if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) - mAnimation->play(mCurrentGroup, "loop start"); - } } From 9d7ccfda1ffa7edd79b52cc777466c55181296a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 21:07:36 -0800 Subject: [PATCH 0109/1483] Rename CharState_Idle to CharState_Alive --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 5 ++--- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35bca441ae..00350fcc22 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Alive))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); } @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Idle); + iter->second.setState(CharState_Alive); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0b8eff7331..4e861f35c7 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,7 +43,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); switch(mState) { - case CharState_Idle: + case CharState_Alive: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; @@ -121,7 +121,6 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - // set mState = CharState_Idle? if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) { count = std::max(count, 1); @@ -159,7 +158,7 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { - case CharState_Idle: + case CharState_Alive: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 992cb8f1fe..cdbe439a43 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,7 +12,7 @@ namespace MWMechanics { enum CharacterState { - CharState_Idle, + CharState_Alive, CharState_Dead }; From a94947029e41e0337c5163dc1d1fd7d1496fde1d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 00:59:48 -0800 Subject: [PATCH 0110/1483] Check the marker name before deciding what to do with it Also, don't force 'idle' after a playgroup --- apps/openmw/mwmechanics/character.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4e861f35c7..0767df130d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -87,17 +87,24 @@ void CharacterController::markerEvent(const std::string &evt) return; } - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0) { - if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); } + return; } - else if(mAnimQueue.size() > 0) + + if(evt.compare(ms, evt.length()-ms, "stop") == 0) { - if(evt.compare(ms, evt.length()-ms, "stop") == 0) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() > 0) { mAnimQueue.pop_front(); if(mAnimQueue.size() > 0) @@ -106,6 +113,7 @@ void CharacterController::markerEvent(const std::string &evt) mAnimation->play(mCurrentGroup, "start"); } } + return; } } @@ -129,7 +137,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); while(count-- > 0) mAnimQueue.push_back(groupname); - mAnimQueue.push_back("idle"); mCurrentGroup = groupname; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -138,7 +145,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.resize(1); while(count-- > 0) mAnimQueue.push_back(groupname); - mAnimQueue.push_back("idle"); } } } From 5cafc24ee2b619898afdda0914e4da6b79f77464 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 13:43:45 -0800 Subject: [PATCH 0111/1483] Rename CharState_Alive back to CharState_Idle --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 00350fcc22..35bca441ae 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Alive))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); } @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Alive); + iter->second.setState(CharState_Idle); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0767df130d..96221cbb8d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,7 +43,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); switch(mState) { - case CharState_Alive: + case CharState_Idle: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; @@ -164,7 +164,7 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { - case CharState_Alive: + case CharState_Idle: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cdbe439a43..992cb8f1fe 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,7 +12,7 @@ namespace MWMechanics { enum CharacterState { - CharState_Alive, + CharState_Idle, CharState_Dead }; From 3e9b0a333cea79ba76b684bdb83b086c89028432 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 14:25:32 -0800 Subject: [PATCH 0112/1483] Allow specifying the accumulation for animations Animations that move a character may do so either visually or physically. An axis' accumuluation value specifies whether the movement is visual (0) or physical (1). Idle animations, for instance, typically don't physically move a character, while death animations may physically move them along the X and Y planes, but not along Z (the vertical movement is purely visual). --- apps/openmw/mwmechanics/character.cpp | 15 ++++----------- apps/openmw/mwrender/animation.cpp | 9 ++++++++- apps/openmw/mwrender/animation.hpp | 6 ++++++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 96221cbb8d..f5b6301a2b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,17 +41,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - switch(mState) - { - case CharState_Idle: - mCurrentGroup = "idle"; - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_Dead: - mCurrentGroup = "death1"; - mAnimation->play(mCurrentGroup, "stop"); - break; - } + setState(mState); } CharacterController::CharacterController(const CharacterController &rhs) @@ -138,6 +128,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; + mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } else if(mode == 0) @@ -166,10 +157,12 @@ void CharacterController::setState(CharacterState state) { case CharState_Idle: mCurrentGroup = "idle"; + mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); mAnimation->play(mCurrentGroup, "start"); break; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1a464f5d84..b6c712522b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,6 +21,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mInsert(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mAccumulate(Ogre::Vector3::ZERO) , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) @@ -118,6 +119,12 @@ void Animation::setController(MWMechanics::CharacterController *controller) } +void Animation::setAccumulation(const Ogre::Vector3 &accum) +{ + mAccumulate = accum; +} + + void Animation::updatePosition(float time) { mAnimState->setTimePosition(time); @@ -127,7 +134,7 @@ void Animation::updatePosition(float time) /* Update the animation and get the non-accumulation root's difference from the * last update. */ mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); - Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; + Ogre::Vector3 posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 726d0cf388..32d51775a5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -24,6 +24,7 @@ protected: std::map mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; @@ -49,6 +50,11 @@ public: void setController(MWMechanics::CharacterController *controller); std::vector getAnimationNames(); + // Specifies the axis' to accumulate on. Non-accumulated axis will just + // move visually, but not affect the actual movement. Each x/y/z value + // should be on the scale of 0 to 1. + void setAccumulation(const Ogre::Vector3 &accum); + void play(const std::string &groupname, const std::string &start); virtual void runAnimation(float timepassed); }; From c7684cb979bc0c4791d6e88bb9cf626764ed3417 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 14:50:55 -0800 Subject: [PATCH 0113/1483] Pass the key time to markerEvent --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f5b6301a2b..241033802c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -56,7 +56,7 @@ CharacterController::CharacterController(const CharacterController &rhs) } -void CharacterController::markerEvent(const std::string &evt) +void CharacterController::markerEvent(float time, const std::string &evt) { if(evt.compare(0, 7, "sound: ") == 0) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 992cb8f1fe..902b8cc36b 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -32,7 +32,7 @@ class CharacterController protected: /* Called by the animation whenever a new text key is reached. */ - void markerEvent(const std::string &evt); + void markerEvent(float time, const std::string &evt); friend class MWRender::Animation; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b6c712522b..cfc72de379 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -223,13 +223,15 @@ void Animation::runAnimation(float timepassed) break; } + float time = mNextKey->first; const std::string &evt = mNextKey->second; - updatePosition(mNextKey->first); - timepassed = targetTime - mNextKey->first; mNextKey++; + updatePosition(time); + timepassed = targetTime - time; + if(mController) - mController->markerEvent(evt); + mController->markerEvent(time, evt); } } From a527cb8349fd1b4e6b0fa12ac70ab83bb78d4449 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 15:22:14 -0800 Subject: [PATCH 0114/1483] Loop the current animation when not dead This should be better, but it's not perfect. It misses the case where start < loop start == loop stop <= stop --- apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 241033802c..97cdf3f492 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -79,7 +79,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(evt.compare(ms, evt.length()-ms, "loop stop") == 0) { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() == 0) + { + if(time > 0.0f && mState != CharState_Dead) + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); @@ -89,7 +94,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(evt.compare(ms, evt.length()-ms, "stop") == 0) { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() == 0) + { + if(time > 0.0f && mState != CharState_Dead) + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); From 40f8e757637927d631ff97aa4a14d0b7c911bddf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 15:39:28 -0800 Subject: [PATCH 0115/1483] Use a SpecialIdle state for PlayGroup/LoopGroup invoked animations Note that actors will *not* automatically resume a normal idle state afterward. Their AI will need to control what to do when the special idle is finished. --- apps/openmw/mwmechanics/character.cpp | 3 +++ apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 97cdf3f492..73a6f2c9c7 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -138,6 +138,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; + mState = CharState_SpecialIdle; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -165,6 +166,8 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { + case CharState_SpecialIdle: + break; case CharState_Idle: mCurrentGroup = "idle"; mAnimation->setAccumulation(Ogre::Vector3::ZERO); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 902b8cc36b..47bb27e837 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,6 +12,7 @@ namespace MWMechanics { enum CharacterState { + CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, CharState_Dead }; From 9235fba77058e5ade49e5b64f988694ecfde2c2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 16:00:51 -0800 Subject: [PATCH 0116/1483] Store the movement vector in the character controller --- apps/openmw/mwmechanics/actors.cpp | 6 ++++++ apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35bca441ae..396f34eab6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -262,6 +262,12 @@ namespace MWMechanics if(!paused) { + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + iter->second.setDirection(dir); + } + std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 73a6f2c9c7..ff400b9d10 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ Ogre::Vector3 CharacterController::update(float duration) if(mAnimation && !mSkipAnim) mAnimation->runAnimation(duration); mSkipAnim = false; - return MWWorld::Class::get(mPtr).getMovementVector(mPtr); + return mDirection; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 47bb27e837..c151b3b9fd 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWMECHANICS_CHARACTER_HPP #define GAME_MWMECHANICS_CHARACTER_HPP +#include + #include "../mwworld/ptr.hpp" namespace MWRender @@ -27,6 +29,8 @@ class CharacterController typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; + Ogre::Vector3 mDirection; + std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; @@ -46,6 +50,9 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); + void setDirection(const Ogre::Vector3 &dir) + { mDirection = dir; } + void setState(CharacterState state); CharacterState getState() const { return mState; } From 9123f4f2afdc7738087dadf59ee5ddee342ea9e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 16:21:29 -0800 Subject: [PATCH 0117/1483] Return the movement vector from runAnimation --- apps/openmw/mwrender/activatoranimation.cpp | 7 ------- apps/openmw/mwrender/activatoranimation.hpp | 2 -- apps/openmw/mwrender/animation.cpp | 14 +++++++++----- apps/openmw/mwrender/animation.hpp | 4 ++-- apps/openmw/mwrender/creatureanimation.cpp | 12 ++---------- apps/openmw/mwrender/creatureanimation.hpp | 2 -- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.hpp | 2 +- 8 files changed, 16 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 18ae318651..f951307b68 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -54,11 +54,4 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) } } -void ActivatorAnimation::runAnimation(float timepassed) -{ - // Placeholder - - Animation::runAnimation(timepassed); -} - } diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp index f3d8d86c86..f3ea38f447 100644 --- a/apps/openmw/mwrender/activatoranimation.hpp +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -15,8 +15,6 @@ namespace MWRender public: ActivatorAnimation(const MWWorld::Ptr& ptr); virtual ~ActivatorAnimation(); - - virtual void runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cfc72de379..f9fa6e14cd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -125,16 +125,17 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) } -void Animation::updatePosition(float time) +Ogre::Vector3 Animation::updatePosition(float time) { mAnimState->setTimePosition(time); + Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); - Ogre::Vector3 posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; + posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); @@ -150,6 +151,7 @@ void Animation::updatePosition(float time) world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); } } + return posdiff; } void Animation::resetPosition(float time) @@ -212,14 +214,15 @@ void Animation::play(const std::string &groupname, const std::string &start) } } -void Animation::runAnimation(float timepassed) +Ogre::Vector3 Animation::runAnimation(float timepassed) { + Ogre::Vector3 movement = Ogre::Vector3::ZERO; while(mAnimState && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - updatePosition(targetTime); + movement += updatePosition(targetTime); break; } @@ -227,12 +230,13 @@ void Animation::runAnimation(float timepassed) const std::string &evt = mNextKey->second; mNextKey++; - updatePosition(time); + movement += updatePosition(time); timepassed = targetTime - time; if(mController) mController->markerEvent(time, evt); } + return movement; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 32d51775a5..dfa2950f35 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -34,7 +34,7 @@ protected: /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ - void updatePosition(float time); + Ogre::Vector3 updatePosition(float time); /* Updates the animation to the specified time, without moving the mPtr * object. */ void resetPosition(float time); @@ -56,7 +56,7 @@ public: void setAccumulation(const Ogre::Vector3 &accum); void play(const std::string &groupname, const std::string &start); - virtual void runAnimation(float timepassed); + virtual Ogre::Vector3 runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index caa040d952..34b09c0d06 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -8,9 +8,8 @@ #include "../mwbase/world.hpp" -using namespace Ogre; -using namespace NifOgre; -namespace MWRender{ +namespace MWRender +{ CreatureAnimation::~CreatureAnimation() { @@ -55,11 +54,4 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) } } -void CreatureAnimation::runAnimation(float timepassed) -{ - // Placeholder - - Animation::runAnimation(timepassed); -} - } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 5456f857f7..0c277d1985 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -15,8 +15,6 @@ namespace MWRender public: CreatureAnimation(const MWWorld::Ptr& ptr); virtual ~CreatureAnimation(); - - virtual void runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f309ee8990..432a2f5260 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -308,7 +308,7 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int return entities; } -void NpcAnimation::runAnimation(float timepassed) +Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { if(mTimeToChange > .2) { @@ -317,7 +317,7 @@ void NpcAnimation::runAnimation(float timepassed) } mTimeToChange += timepassed; - Animation::runAnimation(timepassed); + return Animation::runAnimation(timepassed); } void NpcAnimation::removeEntities(NifOgre::EntityList &entities) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1610913176..a4e87e7224 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -98,7 +98,7 @@ public: MWWorld::InventoryStore& inv, int visibilityFlags); virtual ~NpcAnimation(); - virtual void runAnimation(float timepassed); + virtual Ogre::Vector3 runAnimation(float timepassed); void forceUpdate(); }; From 1cdd64cd9b0c90cc8b0c78e4e21a3cd90c525df3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 17:05:58 -0800 Subject: [PATCH 0118/1483] Return the animation movement from the character controller. Consequently, dead actors don't move anymore. The doPhysics call apparently isn't moving them. --- apps/openmw/mwmechanics/character.cpp | 19 +++++++++++++++++-- apps/openmw/mwrender/animation.cpp | 10 ---------- apps/openmw/mwrender/animation.hpp | 7 +++---- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ff400b9d10..226f000692 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -120,10 +120,25 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) - mAnimation->runAnimation(duration); + movement += mAnimation->runAnimation(duration); mSkipAnim = false; - return mDirection; + + if(getState() == CharState_SpecialIdle || getState() == CharState_Idle || + getState() == CharState_Dead) + { + // FIXME: mDirection shouldn't influence the movement here. + movement += mDirection; + } + else + { + // FIXME: mDirection should be normalized after setting the speed of + // the animation in setDirection, rather than here. + movement = mDirection.normalisedCopy() * movement.length(); + } + + return movement; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f9fa6e14cd..4d8f9586fb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -140,16 +140,6 @@ Ogre::Vector3 Animation::updatePosition(float time) /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); mLastPosition += posdiff; - - if(mPtr.isInCell()) - { - /* Finally, move the object based on how much the non-accumulation root moved. */ - Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); - newpos += mInsert->getOrientation() * posdiff; - - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); - } } return posdiff; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index dfa2950f35..349871f0a6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -32,11 +32,10 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; - /* Updates the animation to the specified time, and moves the mPtr object - * based on the change since the last update or reset. */ + /* Updates the animation to the specified time, and returns the movement + * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Updates the animation to the specified time, without moving the mPtr - * object. */ + /* Updates the animation to the specified time, without moving anything. */ void resetPosition(float time); float findStart(const std::string &groupname, const std::string &start); From e33f59e0feb124b5436f9ed1b34bbf43bf5f933f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 17:41:36 -0800 Subject: [PATCH 0119/1483] Ensure the direction vector is initialized and copied properly --- apps/openmw/mwmechanics/character.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 226f000692..b6adec0681 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,7 +30,7 @@ namespace MWMechanics { CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -47,7 +47,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; From aecfc0829a70a5539b6e86af91fd73a305888e9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 18:04:00 -0800 Subject: [PATCH 0120/1483] Implement WalkForward and WalkBack character states --- apps/openmw/mwmechanics/actors.cpp | 16 ++++++++++++++++ apps/openmw/mwmechanics/character.cpp | 12 ++++++++++++ apps/openmw/mwmechanics/character.hpp | 4 ++++ 3 files changed, 32 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 396f34eab6..b09bcac4d8 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -251,6 +251,7 @@ namespace MWMechanics } iter->second.setState(CharState_Dead); + iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -264,7 +265,22 @@ namespace MWMechanics { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { + if(iter->second.getState() == CharState_Dead) + continue; + Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + CharacterState newstate = CharState_Idle; + + if(dir.length() >= 0.1f) + { + if(dir.y < 0.0f) + newstate = CharState_WalkBack; + else + newstate = CharState_WalkForward; + } + + if(iter->second.getState() != newstate) + iter->second.setState(newstate); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b6adec0681..f3a1f2fba7 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -188,6 +188,18 @@ void CharacterController::setState(CharacterState state) mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, "start"); break; + + case CharState_WalkForward: + mCurrentGroup = "walkforward"; + mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); + mAnimation->play(mCurrentGroup, "start"); + break; + case CharState_WalkBack: + mCurrentGroup = "walkback"; + mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); + mAnimation->play(mCurrentGroup, "start"); + break; + case CharState_Dead: mCurrentGroup = "death1"; mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c151b3b9fd..f2651b4cfc 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -16,6 +16,10 @@ namespace MWMechanics enum CharacterState { CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, + + CharState_WalkForward, + CharState_WalkBack, + CharState_Dead }; From 0b68953f0d7b4c60e83c2be4e3c3cb4715c0178c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 21:40:47 -0800 Subject: [PATCH 0121/1483] Scale animation speed using the direction length The direction length doesn't currently give a good speed, but it's something. --- apps/openmw/mwmechanics/character.cpp | 24 ++++++++++++++---------- apps/openmw/mwmechanics/character.hpp | 3 +-- apps/openmw/mwrender/animation.cpp | 2 ++ apps/openmw/mwrender/animation.hpp | 4 ++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f3a1f2fba7..ad784d34fb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -118,6 +118,17 @@ void CharacterController::markerEvent(float time, const std::string &evt) } +void CharacterController::setDirection(const Ogre::Vector3 &dir) +{ + // HACK: The direction length we get is too large. + float mult = dir.length() / 32.0f; + mult = std::max(1.0f, mult); + if(mAnimation) + mAnimation->setSpeedMult(mult); + mDirection = dir.normalisedCopy(); +} + + Ogre::Vector3 CharacterController::update(float duration) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; @@ -125,17 +136,10 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(getState() == CharState_SpecialIdle || getState() == CharState_Idle || - getState() == CharState_Dead) + if(!(getState() == CharState_SpecialIdle || getState() == CharState_Idle || + getState() == CharState_Dead)) { - // FIXME: mDirection shouldn't influence the movement here. - movement += mDirection; - } - else - { - // FIXME: mDirection should be normalized after setting the speed of - // the animation in setDirection, rather than here. - movement = mDirection.normalisedCopy() * movement.length(); + movement = mDirection * movement.length(); } return movement; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index f2651b4cfc..9a82f890d4 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -54,8 +54,7 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setDirection(const Ogre::Vector3 &dir) - { mDirection = dir; } + void setDirection(const Ogre::Vector3 &dir); void setState(CharacterState state); CharacterState getState() const diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4d8f9586fb..a86e14c83b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mAnimSpeedMult(1.0f) { } @@ -207,6 +208,7 @@ void Animation::play(const std::string &groupname, const std::string &start) Ogre::Vector3 Animation::runAnimation(float timepassed) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; + timepassed *= mAnimSpeedMult; while(mAnimState && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 349871f0a6..6c8357d59e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,7 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + float mAnimSpeedMult; /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ @@ -54,6 +55,9 @@ public: // should be on the scale of 0 to 1. void setAccumulation(const Ogre::Vector3 &accum); + void setSpeedMult(float speedmult) + { mAnimSpeedMult = speedmult; } + void play(const std::string &groupname, const std::string &start); virtual Ogre::Vector3 runAnimation(float timepassed); }; From 2d96f528646e0799837ad29463b97c548f1d3df9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 19 Jan 2013 14:29:14 +0100 Subject: [PATCH 0122/1483] select correct record when opening a dialogue sub view --- apps/opencs/view/world/dialoguesubview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 6138fd3f5e..2bf6577b11 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -10,6 +10,7 @@ #include #include "../../model/world/columnbase.hpp" +#include "../../model/world/idtable.hpp" CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete) @@ -83,7 +84,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM } } - mWidgetMapper->toFirst(); /// \todo use the correct row instead + mWidgetMapper->setCurrentModelIndex ( + dynamic_cast (*model).getModelIndex (id.getId(), 0)); } void CSVWorld::DialogueSubView::setEditLock (bool locked) From de2d084e6182b5c9ff328491f32a43f28b6624a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 14:22:15 -0800 Subject: [PATCH 0123/1483] Add a looping property to handle if an animation should loop --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- apps/openmw/mwmechanics/character.cpp | 15 +++++++++------ apps/openmw/mwmechanics/character.hpp | 5 +++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index b09bcac4d8..76e02ed36d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,9 +169,9 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); else - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Idle); + iter->second.setState(CharState_Idle, true); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) @@ -250,7 +250,7 @@ namespace MWMechanics continue; } - iter->second.setState(CharState_Dead); + iter->second.setState(CharState_Dead, false); iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -280,7 +280,7 @@ namespace MWMechanics } if(iter->second.getState() != newstate) - iter->second.setState(newstate); + iter->second.setState(newstate, true); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ad784d34fb..5127b65641 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,8 +29,8 @@ namespace MWMechanics { -CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) +CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -41,13 +41,14 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - setState(mState); + setState(mState, loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mLoop(rhs.mLoop) { if(mAnimNames.size() == 0) return; @@ -81,7 +82,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) { if(mAnimQueue.size() == 0) { - if(time > 0.0f && mState != CharState_Dead) + if(time > 0.0f && mLoop) mAnimation->play(mCurrentGroup, "loop start"); } else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) @@ -96,7 +97,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) { if(mAnimQueue.size() == 0) { - if(time > 0.0f && mState != CharState_Dead) + if(time > 0.0f && mLoop) mAnimation->play(mCurrentGroup, "loop start"); } else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) @@ -158,6 +159,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; + mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -176,9 +178,10 @@ void CharacterController::skipAnim() } -void CharacterController::setState(CharacterState state) +void CharacterController::setState(CharacterState state, bool loop) { mState = state; + mLoop = loop; if(mAnimNames.size() == 0) return; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9a82f890d4..d773c85b25 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -38,6 +38,7 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; + bool mLoop; protected: /* Called by the animation whenever a new text key is reached. */ @@ -46,7 +47,7 @@ protected: friend class MWRender::Animation; public: - CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); Ogre::Vector3 update(float duration); @@ -56,7 +57,7 @@ public: void setDirection(const Ogre::Vector3 &dir); - void setState(CharacterState state); + void setState(CharacterState state, bool loop); CharacterState getState() const { return mState; } }; From a8e02779b26e0e7b21761b3489ae58917b28181d Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 19 Jan 2013 23:33:18 +0100 Subject: [PATCH 0124/1483] - Add support for multiple plugins trying to modify the same reference - Fix a small signed/unsigned warning --- apps/openmw/mwworld/cellstore.cpp | 56 +++++++++++++++++++++++ apps/openmw/mwworld/esmstore.cpp | 6 +-- apps/openmw/mwworld/esmstore.hpp | 3 ++ apps/openmw/mwworld/store.hpp | 45 ++++++++++++++++--- components/esm/loadcell.cpp | 74 ++++++++++++++++++++++++------- components/esm/loadcell.hpp | 46 ++++++++++++++++++- 6 files changed, 203 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index d007ff9811..ecc1bc3067 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -96,6 +96,11 @@ namespace MWWorld // Get each reference in turn while(mCell->getNextRef(esm[index], ref)) { + // Don't load reference if it was moved to a different cell. + if (mCell->mMovedRefs.find(ref.mRefnum) != mCell->mMovedRefs.end()) { + continue; + } + std::string lowerCase; std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), @@ -139,5 +144,56 @@ namespace MWWorld } } } + + // Load moved references, from separately tracked list. + for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); it++) + { + // Doesn't seem to work in one line... huh? Too sleepy to check... + //const ESM::CellRef &ref0 = it->second; + ESM::CellRef &ref = const_cast(it->second); + + std::string lowerCase; + + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + int rec = store.find(ref.mRefID); + + ref.mRefID = lowerCase; + + /* We can optimize this further by storing the pointer to the + record itself in store.all, so that we don't need to look it + up again here. However, never optimize. There are infinite + opportunities to do that later. + */ + switch(rec) + { + case ESM::REC_ACTI: mActivators.load(ref, store); break; + case ESM::REC_ALCH: mPotions.load(ref, store); break; + case ESM::REC_APPA: mAppas.load(ref, store); break; + case ESM::REC_ARMO: mArmors.load(ref, store); break; + case ESM::REC_BOOK: mBooks.load(ref, store); break; + case ESM::REC_CLOT: mClothes.load(ref, store); break; + case ESM::REC_CONT: mContainers.load(ref, store); break; + case ESM::REC_CREA: mCreatures.load(ref, store); break; + case ESM::REC_DOOR: mDoors.load(ref, store); break; + case ESM::REC_INGR: mIngreds.load(ref, store); break; + case ESM::REC_LEVC: mCreatureLists.load(ref, store); break; + case ESM::REC_LEVI: mItemLists.load(ref, store); break; + case ESM::REC_LIGH: mLights.load(ref, store); break; + case ESM::REC_LOCK: mLockpicks.load(ref, store); break; + case ESM::REC_MISC: mMiscItems.load(ref, store); break; + case ESM::REC_NPC_: mNpcs.load(ref, store); break; + case ESM::REC_PROB: mProbes.load(ref, store); break; + case ESM::REC_REPA: mRepairs.load(ref, store); break; + case ESM::REC_STAT: mStatics.load(ref, store); break; + case ESM::REC_WEAP: mWeapons.load(ref, store); break; + + case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break; + default: + std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; + } + + } } } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 54050b38c7..38fadca9ea 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -30,13 +30,13 @@ void ESMStore::load(ESM::ESMReader &esm) // Cache parent esX files by tracking their indices in the global list of // all files/readers used by the engine. This will greaty help to accelerate // parsing of reference IDs. - size_t index = ~0; + int index = ~0; const ESM::ESMReader::MasterList &masters = esm.getMasters(); std::vector *allPlugins = esm.getGlobalReaderList(); for (size_t j = 0; j < masters.size(); j++) { ESM::MasterData &mast = const_cast(masters[j]); std::string fname = mast.name; - for (size_t i = 0; i < esm.getIndex(); i++) { + for (int i = 0; i < esm.getIndex(); i++) { const std::string &candidate = allPlugins->at(i).getContext().filename; std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); if (fname == fnamecandidate) { @@ -44,7 +44,7 @@ void ESMStore::load(ESM::ESMReader &esm) break; } } - if (index == (size_t)~0) { + if (index == (int)~0) { // Tried to load a parent file that has not been loaded yet. This is bad, // the launcher should have taken care of this. std::string fstring = "File " + fname + " asks for parent file " + masters[j].name diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index bd8e003f4a..2039a00dbb 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -94,6 +94,9 @@ namespace MWWorld ESMStore() : mDynamicCount(0) { + // Cell store needs access to this for tracking moved references + mCells.mEsmStore = this; + mStores[ESM::REC_ACTI] = &mActivators; mStores[ESM::REC_ALCH] = &mPotions; mStores[ESM::REC_APPA] = &mAppas; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 77c9c73574..c36e84813d 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -399,8 +399,7 @@ namespace MWWorld DynamicInt mDynamicInt; DynamicExt mDynamicExt; - - + const ESM::Cell *search(const ESM::Cell &cell) const { if (cell.isExterior()) { return search(cell.getGridX(), cell.getGridY()); @@ -409,6 +408,8 @@ namespace MWWorld } public: + ESMStore *mEsmStore; + typedef SharedIterator iterator; Store() @@ -450,6 +451,30 @@ namespace MWWorld return 0; } + const ESM::Cell *searchOrCreate(int x, int y) { + ESM::Cell cell; + cell.mData.mX = x, cell.mData.mY = y; + + std::pair key(x, y); + std::map, ESM::Cell>::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); + } + + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + ESM::Cell *newCell = new ESM::Cell; + newCell->mData.mX = x; + newCell->mData.mY = y; + mExt[std::make_pair(x, y)] = *newCell; + delete newCell; + + return &mExt[std::make_pair(x, y)]; + } + const ESM::Cell *find(const std::string &id) const { const ESM::Cell *ptr = search(id); if (ptr == 0) { @@ -500,7 +525,7 @@ namespace MWWorld cell->mName = id; // The cell itself takes care of all the hairy details - cell->load(esm); + cell->load(esm, *mEsmStore); if(cell->mData.mFlags & ESM::Cell::Interior) { @@ -515,7 +540,6 @@ namespace MWWorld *oldcell = *cell; } else mInt[idLower] = *cell; - delete cell; } else { @@ -526,12 +550,23 @@ namespace MWWorld oldcell->mContextList.push_back(cell->mContextList.at(0)); // copy list into new cell cell->mContextList = oldcell->mContextList; + // merge lists of leased references, use newer data in case of conflict + for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) { + // remove reference from current leased ref tracker and add it to new cell + if (oldcell->mMovedRefs.find(it->second.mRefnum) != oldcell->mMovedRefs.end()) { + ESM::MovedCellRef target0 = oldcell->mMovedRefs[it->second.mRefnum]; + ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); + wipecell->mLeasedRefs.erase(it->second.mRefnum); + } + oldcell->mMovedRefs[it->second.mRefnum] = it->second; + } + cell->mMovedRefs = oldcell->mMovedRefs; // have new cell replace old cell *oldcell = *cell; } else mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; - delete cell; } + delete cell; } iterator intBegin() const { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index aafe629e64..76a1e4f951 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -2,11 +2,15 @@ #include #include -#include +#include +#include #include "esmreader.hpp" #include "esmwriter.hpp" +#include +#include + namespace ESM { @@ -64,10 +68,11 @@ void CellRef::save(ESMWriter &esm) } } -void Cell::load(ESMReader &esm) +void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) { // Ignore this for now, it might mean we should delete the entire // cell? + // TODO: treat the special case "another plugin moved this ref, but we want to delete it"! if (esm.isNextSub("DELE")) { esm.skipHSub(); } @@ -110,6 +115,33 @@ void Cell::load(ESMReader &esm) if (esm.isNextSub("NAM0")) { esm.getHT(mNAM0); } + + // preload moved references + while (esm.isNextSub("MVRF")) { + CellRef ref; + MovedCellRef cMRef; + getNextMVRF(esm, cMRef); + + MWWorld::Store &cStore = const_cast&>(store.get()); + ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following + // implementation when the oher implementation works as well. + getNextRef(esm, ref); + std::string lowerCase; + + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + // Add data required to make reference appear in the correct cell. + /* + std::cout << "Moving refnumber! First cell: " << mData.mX << " " << mData.mY << std::endl; + std::cout << " New cell: " << cMRef.mTarget[0] << " " << cMRef.mTarget[0] << std::endl; + std::cout << "Refnumber (MVRF): " << cMRef.mRefnum << " (FRMR) " << ref.mRefnum << std::endl; + */ + mMovedRefs[cMRef.mRefnum] = cMRef; + cellAlt->mLeasedRefs[ref.mRefnum] = ref; + } // Save position of the cell references and move on mContextList.push_back(esm.getContext()); @@ -171,23 +203,15 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; - + + // NOTE: We should not need this check. It is a safety check until we have checked + // more plugins, and how they treat these moved references. if (esm.isNextSub("MVRF")) { - // Moved existing reference across cell boundaries, so interpret the blocks correctly. - // FIXME: Right now, we don't do anything with this data. This might result in weird behaviour, - // where a moved reference does not appear because the owning cell (i.e. this cell) is not - // loaded in memory. - int movedRefnum = 0; - int destCell[2]; - esm.getHT(movedRefnum); - esm.getHNT(destCell, "CNDT"); - // TODO: Figure out what happens when a reference has moved into an interior cell. This might - // be required for NPCs following the player. + esm.skipRecord(); // skip MVRF + esm.skipRecord(); // skip CNDT + // That should be it, I haven't seen any other fields yet. } - // If we have just parsed a MVRF entry, there should be a regular FRMR entry following right there. - // With the exception that this bock technically belongs to a different cell than this one. - // TODO: Figure out a way to handle these weird references that do not belong to this cell. - // This may require some not-so-small behing-the-scenes updates. + esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); @@ -293,4 +317,20 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) return true; } +bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) +{ + esm.getHT(mref.mRefnum); + esm.getHNOT(mref.mTarget, "CNDT"); + + // Identify references belonging to a parent file and adapt the ID accordingly. + int local = (mref.mRefnum & 0xff000000) >> 24; + size_t global = esm.getIndex() + 1; + mref.mRefnum &= 0x00ffffff; // delete old plugin ID + const ESM::ESMReader::MasterList &masters = esm.getMasters(); + global = masters[local-1].index + 1; + mref.mRefnum |= global << 24; // insert global plugin ID + + return true; +} + } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index dff5a33387..6862dbc5c3 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -6,6 +6,14 @@ #include "esmcommon.hpp" #include "defs.hpp" +#include + +/* +namespace MWWorld { + class ESMStore; + class CellStore; +} +*/ namespace ESM { @@ -86,6 +94,26 @@ public: void save(ESMWriter &esm); }; +/* Moved cell reference tracking object. This mainly stores the target cell + of the reference, so we can easily know where it has been moved when another + plugin tries to move it independently. + */ +class MovedCellRef +{ +public: + int mRefnum; + + // Target cell (if exterior) + int mTarget[2]; + + // TODO: Support moving references between exterior and interior cells! + // This may happen in saves, when an NPC follows the player. Tribunal + // introduces a henchman (which no one uses), so we may need this as well. +}; + +typedef std::map MovedCellRefTracker; +typedef std::map CellRefTracker; + /* Cells hold data about objects, creatures, statics (rocks, walls, buildings) and landscape (for exterior cells). Cells frequently also has other associated LAND and PGRD records. Combined, all this @@ -131,8 +159,17 @@ struct Cell bool mWaterInt; int mMapColor; int mNAM0; - - void load(ESMReader &esm); + + // References "leased" from another cell (i.e. a different cell + // introduced this ref, and it has been moved here by a plugin) + CellRefTracker mLeasedRefs; + MovedCellRefTracker mMovedRefs; + + void load(ESMReader &esm, MWWorld::ESMStore &store); + + // This method is left in for compatibility with esmtool. Parsing moved references currently requires + // passing ESMStore, bit it does not know about this parameter, so we do it this way. + void load(ESMReader &esm) {}; void save(ESMWriter &esm); bool isExterior() const @@ -167,6 +204,11 @@ struct Cell reuse one memory location without blanking it between calls. */ static bool getNextRef(ESMReader &esm, CellRef &ref); + + /* This fetches an MVRF record, which is used to track moved references. + * Since they are comparably rare, we use a separate method for this. + */ + static bool getNextMVRF(ESMReader &esm, MovedCellRef &mref); }; } #endif From e0541b52c4321a8535516590de0df40ec0d98436 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 14:56:24 -0800 Subject: [PATCH 0125/1483] Use a list to store and get state information --- apps/openmw/mwmechanics/character.cpp | 67 ++++++++++++++++----------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5127b65641..a494008236 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,6 +19,8 @@ #include "character.hpp" +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" @@ -29,6 +31,35 @@ namespace MWMechanics { +static const struct { + CharacterState state; + const char groupname[32]; + Ogre::Vector3 accumulate; +} sStateList[] = { + { CharState_SpecialIdle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle, "idle", Ogre::Vector3::ZERO }, + + { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + + { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, +}; +static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); + +static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 *accum) +{ + for(size_t i = 0;i < sStateListSize;i++) + { + if(sStateList[i].state == state) + { + *group = sStateList[i].groupname; + *accum = sStateList[i].accumulate; + return; + } + } + throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(state)); +} + CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { @@ -41,7 +72,11 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - setState(mState, loop); + + Ogre::Vector3 accum; + getStateInfo(mState, &mCurrentGroup, &accum); + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "stop"); } CharacterController::CharacterController(const CharacterController &rhs) @@ -186,33 +221,11 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimNames.size() == 0) return; mAnimQueue.clear(); - switch(mState) - { - case CharState_SpecialIdle: - break; - case CharState_Idle: - mCurrentGroup = "idle"; - mAnimation->setAccumulation(Ogre::Vector3::ZERO); - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_WalkForward: - mCurrentGroup = "walkforward"; - mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_WalkBack: - mCurrentGroup = "walkback"; - mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - - case CharState_Dead: - mCurrentGroup = "death1"; - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - } + Ogre::Vector3 accum; + getStateInfo(mState, &mCurrentGroup, &accum); + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "start"); } } From a7b07ee5cf2ed697ce43dbe0283ac7554c106010 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 15:44:57 -0800 Subject: [PATCH 0126/1483] Don't reset the animation when setting the same state Unless looping is being toggled on. --- apps/openmw/mwmechanics/actors.cpp | 3 +-- apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 76e02ed36d..8c6da4a318 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -279,8 +279,7 @@ namespace MWMechanics newstate = CharState_WalkForward; } - if(iter->second.getState() != newstate) - iter->second.setState(newstate, true); + iter->second.setState(newstate, true); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a494008236..7e52ef3d82 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -215,8 +215,18 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { - mState = state; - mLoop = loop; + if(mState == state) + { + // If setting the same state again, only reset the animation if looping + // is being turned on. + if(mLoop == loop || !(mLoop=loop)) + return; + } + else + { + mState = state; + mLoop = loop; + } if(mAnimNames.size() == 0) return; From d6b956cdcf45715329d080deb0783c74244821dd Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 15 Jan 2013 08:27:58 -0800 Subject: [PATCH 0127/1483] fixed swapped day & month fields when created a stamped journal entry --- apps/openmw/mwdialogue/journalentry.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index e6141884cb..5ffde54991 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -61,8 +61,8 @@ namespace MWDialogue StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index) { int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong; - int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong; - int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong; + int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong; + int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong; return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth); } From 68779375b2aa6dd1e722d2460c15d37a17403aed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 16:19:47 -0800 Subject: [PATCH 0128/1483] Implement WalkLeft and WalkRight character states --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++++- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwmechanics/character.hpp | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8c6da4a318..6c69c457bb 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -273,7 +273,14 @@ namespace MWMechanics if(dir.length() >= 0.1f) { - if(dir.y < 0.0f) + if(std::abs(dir.x/2.0f) > std::abs(dir.y)) + { + if(dir.x > 0.0f) + newstate = CharState_WalkRight; + else if(dir.x < 0.0f) + newstate = CharState_WalkLeft; + } + else if(dir.y < 0.0f) newstate = CharState_WalkBack; else newstate = CharState_WalkForward; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7e52ef3d82..262945c024 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,6 +41,8 @@ static const struct { { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, + { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, }; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d773c85b25..6d8b3386c1 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -19,6 +19,8 @@ enum CharacterState { CharState_WalkForward, CharState_WalkBack, + CharState_WalkLeft, + CharState_WalkRight, CharState_Dead }; From 528c3da6dae85a8c4c1903b16b3322742ca02292 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 19 Jan 2013 16:20:22 -0800 Subject: [PATCH 0129/1483] record heard topics in journal --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index b83f495ad9..a3bb640e69 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -20,6 +20,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/journal.hpp" #include "../mwbase/scriptmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -269,6 +270,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + MWBase::Environment::get().getJournal()->addTopic (topic, info->mId); executeScript (info->mResultScript); @@ -420,6 +422,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); + MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); executeScript (info->mResultScript); mLastTopic = mLastTopic; mLastDialogue = *info; From 4c7ae3d1ff296b4c7cc96fcd2c533de3ace00443 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 19 Jan 2013 16:21:15 -0800 Subject: [PATCH 0130/1483] prevent duplicate journal entries from being recorded --- apps/openmw/mwdialogue/journalimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 2b2c603819..c623ddc85c 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -31,6 +31,12 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index) { + // bail out of we already have heard this... + auto infoId = JournalEntry::idFromIndex (id, index); + for (auto i = mJournal.begin (); i != mJournal.end (); ++i) + if (i->mTopic == id && i->mInfoId == infoId) + return; + StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index); mJournal.push_back (entry); From f55da179337a2591438f8ccad5cd9231203dce77 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 19 Jan 2013 16:21:41 -0800 Subject: [PATCH 0131/1483] made some journal accessor methods constant --- apps/openmw/mwdialogue/topic.cpp | 6 +++--- apps/openmw/mwdialogue/topic.hpp | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index b6e7c07ae2..3253b20d66 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -27,17 +27,17 @@ namespace MWDialogue mEntries.push_back (entry.mInfoId); } - Topic::TEntryIter Topic::begin() + Topic::TEntryIter Topic::begin() const { return mEntries.begin(); } - Topic::TEntryIter Topic::end() + Topic::TEntryIter Topic::end() const { return mEntries.end(); } - JournalEntry Topic::getEntry (const std::string& infoId) + JournalEntry Topic::getEntry (const std::string& infoId) const { return JournalEntry (mTopic, infoId); } diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp index 566f60ab00..c3f0baabc2 100644 --- a/apps/openmw/mwdialogue/topic.hpp +++ b/apps/openmw/mwdialogue/topic.hpp @@ -34,13 +34,15 @@ namespace MWDialogue /// /// \note Redundant entries are ignored. - TEntryIter begin(); + std::string const & getName () const { return mTopic; } + + TEntryIter begin() const; ///< Iterator pointing to the begin of the journal for this topic. - TEntryIter end(); + TEntryIter end() const; ///< Iterator pointing past the end of the journal for this topic. - JournalEntry getEntry (const std::string& infoId); + JournalEntry getEntry (const std::string& infoId) const; }; } From 85ca1e993f312594f4e0a77b12d3be625f218f46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 21:55:04 -0800 Subject: [PATCH 0132/1483] Properly check if an animation exists before playing it --- apps/openmw/mwmechanics/character.cpp | 34 +++++++++++++-------------- apps/openmw/mwmechanics/character.hpp | 2 -- apps/openmw/mwrender/animation.cpp | 18 +++----------- apps/openmw/mwrender/animation.hpp | 3 ++- 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 262945c024..ea934a2841 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -65,29 +65,24 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { - if(mAnimation) - mAnimNames = mAnimation->getAnimationNames(); - if(mAnimNames.size() == 0) - { - mAnimation = NULL; + if(!mAnimation) return; - } mAnimation->setController(this); Ogre::Vector3 accum; getStateInfo(mState, &mCurrentGroup, &accum); mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "stop"); + if(mAnimation->hasAnimation(mCurrentGroup)) + mAnimation->play(mCurrentGroup, "stop"); } CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) - , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) - , mLoop(rhs.mLoop) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) + , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim), mLoop(rhs.mLoop) { - if(mAnimNames.size() == 0) + if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -186,7 +181,7 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) + if(mAnimation && mAnimation->hasAnimation(groupname)) { count = std::max(count, 1); if(mode != 0 || mAnimQueue.size() == 0) @@ -230,14 +225,19 @@ void CharacterController::setState(CharacterState state, bool loop) mLoop = loop; } - if(mAnimNames.size() == 0) + if(!mAnimation) return; mAnimQueue.clear(); + std::string anim; Ogre::Vector3 accum; - getStateInfo(mState, &mCurrentGroup, &accum); - mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "start"); + getStateInfo(mState, &anim, &accum); + if(mAnimation->hasAnimation(anim)) + { + mCurrentGroup = anim; + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "start"); + } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6d8b3386c1..43ff21dfb2 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -30,8 +30,6 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - std::vector mAnimNames; - typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a86e14c83b..67be0bf0c5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -100,17 +100,9 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } -std::vector Animation::getAnimationNames() +bool Animation::hasAnimation(const std::string &anim) { - std::vector anims; - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); - while(ai.hasMoreElements()) - anims.push_back(ai.getNext()->getAnimationName()); - } - return anims; + return mEntityList.mSkelBase && mEntityList.mSkelBase->hasAnimationState(anim); } @@ -188,13 +180,9 @@ float Animation::findStart(const std::string &groupname, const std::string &star void Animation::play(const std::string &groupname, const std::string &start) { try { - if(!mEntityList.mSkelBase) - throw std::runtime_error("Attempting to animate an inanimate object"); - - Ogre::AnimationState *newstate = mEntityList.mSkelBase->getAnimationState(groupname); if(mAnimState) mAnimState->setEnabled(false); - mAnimState = newstate; + mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); mCurrentKeys = &mTextKeys[groupname]; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6c8357d59e..50ddc34d5c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -48,7 +48,8 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); - std::vector getAnimationNames(); + + bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just // move visually, but not affect the actual movement. Each x/y/z value From 3c6ddd7fa783068477a5d0e91605b2037803558e Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 14:10:04 +0000 Subject: [PATCH 0133/1483] fixed isInCell method --- apps/openmw/mwworld/containerstore.cpp | 1 + apps/openmw/mwworld/ptr.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 6884aa6c8e..7a4120d0a4 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -90,6 +90,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) cell = player.getCell(); item.mCell = cell; + item.mContainerStore = 0; MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); } diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 594ddef2d5..d97ebcc6ea 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -74,7 +74,7 @@ namespace MWWorld bool isInCell() const { - return (mCell != 0); + return (mContainerStore == 0); } void setContainerStore (ContainerStore *store); From 665a530e10c912e5159929f7e4fcb5300d9559a4 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 14:14:34 +0000 Subject: [PATCH 0134/1483] renamed realAdd to addImp --- apps/openmw/mwworld/containerstore.cpp | 6 +++--- apps/openmw/mwworld/containerstore.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 7a4120d0a4..bca4073b52 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -74,7 +74,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) { - MWWorld::ContainerStoreIterator it = realAdd(ptr); + MWWorld::ContainerStoreIterator it = addImp(ptr); MWWorld::Ptr item = *it; std::string script = MWWorld::Class::get(item).getScript(item); @@ -97,7 +97,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) return it; } -MWWorld::ContainerStoreIterator MWWorld::ContainerStore::realAdd (const Ptr& ptr) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) { int type = getType(ptr); @@ -189,7 +189,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor } ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) - realAdd (ref.getPtr()); + addImp (ref.getPtr()); } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e274ee130e..e4f75d5478 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -52,7 +52,7 @@ namespace MWWorld int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; - ContainerStoreIterator realAdd (const Ptr& ptr); + ContainerStoreIterator addImp (const Ptr& ptr); public: From abe25c5f662def09b98ac7afe076258e439294a0 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 14:24:55 +0000 Subject: [PATCH 0135/1483] removed use of c++11 auto --- apps/openmw/mwdialogue/journalimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index c623ddc85c..5e2bc6bc01 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -32,8 +32,8 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index) { // bail out of we already have heard this... - auto infoId = JournalEntry::idFromIndex (id, index); - for (auto i = mJournal.begin (); i != mJournal.end (); ++i) + std::string infoId = JournalEntry::idFromIndex (id, index); + for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i) if (i->mTopic == id && i->mInfoId == infoId) return; From bbac63bff7cd2f16f00c2c9cde102f1dbdbb7c02 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 14:25:44 +0000 Subject: [PATCH 0136/1483] Ignore vim swap files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9734ac35c3..776e2b6591 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ makefile data *.kdev4 CMakeLists.txt.user +*.swp +*.swo From 28c580d2805ee7a88a6a00b2fae573eac3f8807f Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 15:43:52 +0000 Subject: [PATCH 0137/1483] disabling and enabling containers causes scripts on contents to be disabled and enabled accordingly --- apps/openmw/mwworld/worldimp.cpp | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 716cd6e961..bd48875e79 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -406,6 +406,24 @@ namespace MWWorld if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); + + /* run scripts on container contents */ + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + item.mCell = reference.getCell(); + mLocalScripts.add (script, item); + } + } + } if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); @@ -417,6 +435,23 @@ namespace MWWorld if (reference.getRefData().isEnabled()) { reference.getRefData().disable(); + + /* remove scripts on container contents */ + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + mLocalScripts.remove (item); + } + } + } if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); From 23dada0ee4e4d35ff14983a6ff515b30d228b7cb Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 16:38:56 +0000 Subject: [PATCH 0138/1483] moved script handling on enable / disable into their own functions --- apps/openmw/mwworld/worldimp.cpp | 76 ++++++++++++++++++-------------- apps/openmw/mwworld/worldimp.hpp | 3 ++ 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bd48875e79..ee18e5d953 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -401,34 +401,57 @@ namespace MWWorld return MWWorld::Ptr(); } + void World::addContainerScripts(const Ptr& reference, Ptr::CellStore * cell) + { + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + item.mCell = cell; + mLocalScripts.add (script, item); + } + } + } + } + void World::enable (const Ptr& reference) { if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); - /* run scripts on container contents */ - if( reference.getTypeName()==typeid (ESM::Container).name() || - reference.getTypeName()==typeid (ESM::NPC).name() || - reference.getTypeName()==typeid (ESM::Creature).name()) - { - MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); - for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) - { - std::string script = MWWorld::Class::get(*it).getScript(*it); - if(script != "") - { - MWWorld::Ptr item = *it; - item.mCell = reference.getCell(); - mLocalScripts.add (script, item); - } - } - } + addContainerScripts(reference, reference.getCell()); if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); } } + + void World::removeContainerScripts(const Ptr& reference) + { + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + mLocalScripts.remove (item); + } + } + } + } void World::disable (const Ptr& reference) { @@ -436,22 +459,9 @@ namespace MWWorld { reference.getRefData().disable(); - /* remove scripts on container contents */ - if( reference.getTypeName()==typeid (ESM::Container).name() || - reference.getTypeName()==typeid (ESM::NPC).name() || - reference.getTypeName()==typeid (ESM::Creature).name()) - { - MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); - for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) - { - std::string script = MWWorld::Class::get(*it).getScript(*it); - if(script != "") - { - MWWorld::Ptr item = *it; - mLocalScripts.remove (item); - } - } - } + removeContainerScripts(reference); + if(MWWorld::Class::get(reference).getScript(reference) != "") + mLocalScripts.remove(reference); if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 905e6fd966..fa5b41038d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -105,6 +105,9 @@ namespace MWWorld float getNpcActivationDistance (); float getObjectActivationDistance (); + void removeContainerScripts(const Ptr& reference); + void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell); + public: World (OEngine::Render::OgreRenderer& renderer, From 951eb1b236b600ad6c35888649c79bbe8b59e5e8 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 16 Jan 2013 20:10:20 +0100 Subject: [PATCH 0139/1483] Dialogue: return a response from "Info Refusal" when disposition is not satisfied --- apps/openmw/mwdialogue/filter.cpp | 42 +++++++++++++++++++++++++------ apps/openmw/mwdialogue/filter.hpp | 32 +++++++++++------------ 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 99be5554a5..d515c3ac42 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -121,6 +121,13 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const return true; } +bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const +{ + int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + + return actorDisposition >= info.mData.mDisposition; +} + bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name()) @@ -547,17 +554,38 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) {} -bool MWDialogue::Filter::operator() (const ESM::DialInfo& info) const -{ - return testActor (info) && testPlayer (info) && testSelectStructs (info); -} - const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const { + bool infoRefusal = false; + + // Iterate over topic responses to find a matching one for (std::vector::const_iterator iter = dialogue.mInfo.begin(); iter!=dialogue.mInfo.end(); ++iter) - if ((*this) (*iter)) - return &*iter; + { + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) + { + if (testDisposition (*iter)) + return &*iter; + else + infoRefusal = true; + } + } + + if (infoRefusal) + { + // No response is valid because of low NPC disposition, + // search a response in the topic "Info Refusal" + + const MWWorld::Store &dialogues = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Dialogue& infoRefusalDialogue = *dialogues.find ("Info Refusal"); + + for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); + iter!=infoRefusalDialogue.mInfo.end(); ++iter) + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) + return &*iter; + } return 0; } diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 7c8f1116fb..aa8934bfc4 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -18,39 +18,39 @@ namespace MWDialogue MWWorld::Ptr mActor; int mChoice; bool mTalkedToPlayer; - + bool testActor (const ESM::DialInfo& info) const; ///< Is this the right actor for this \a info? - + bool testPlayer (const ESM::DialInfo& info) const; ///< Do the player and the cell the player is currently in match \a info? - + bool testSelectStructs (const ESM::DialInfo& info) const; ///< Are all select structs matching? - + + bool testDisposition (const ESM::DialInfo& info) const; + ///< Is the actor disposition toward the player high enough? + bool testSelectStruct (const SelectWrapper& select) const; - + bool testSelectStructNumeric (const SelectWrapper& select) const; - + int getSelectStructInteger (const SelectWrapper& select) const; - + bool getSelectStructBoolean (const SelectWrapper& select) const; - + int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const; - + bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId, int rank) const; bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId, int rank) const; - - public: - - Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - bool operator() (const ESM::DialInfo& info) const; - ///< \return does the dialogue match? - + public: + + Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); + const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const; }; } From 05796d85a4e4d659ba4a0d61f5e7fa6be3dfacb3 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 19 Jan 2013 02:43:55 +0100 Subject: [PATCH 0140/1483] NPC: take stats from NPDT12 into account Some available stats (level, reputation and disposition) were not used for NPC with auto-calculated stats. --- apps/openmw/mwclass/npc.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 586f9638d3..cfbc64b87d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -100,14 +100,15 @@ namespace MWClass } else { - /// \todo do something with mNpdt12 maybe:p for (int i=0; i<8; ++i) data->mCreatureStats.getAttribute (i).set (10); for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); - data->mCreatureStats.setLevel (1); + data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 43e85ea0c65301c28f83b053ca65847460815e72 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 20 Jan 2013 01:54:35 +0100 Subject: [PATCH 0141/1483] Disallow redirection to info refusal for greetings --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 9 +++++---- apps/openmw/mwdialogue/filter.cpp | 15 +++++++++++++-- apps/openmw/mwdialogue/filter.hpp | 7 ++++++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index a3bb640e69..a8e6a98c9d 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -139,7 +139,8 @@ namespace MWDialogue { if(it->mType == ESM::Dialogue::Greeting) { - if (const ESM::DialInfo *info = filter.search (*it)) + // Search a response (we do not accept a fallback to "Info refusal" here) + if (const ESM::DialInfo *info = filter.search (*it, false)) { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); @@ -248,7 +249,7 @@ namespace MWDialogue const ESM::Dialogue& dialogue = *dialogues.find (topic); - if (const ESM::DialInfo *info = filter.search (dialogue)) + if (const ESM::DialInfo *info = filter.search (dialogue, true)) { parseText (info->mResponse); @@ -295,7 +296,7 @@ namespace MWDialogue { if (iter->mType == ESM::Dialogue::Topic) { - if (filter.search (*iter)) + if (filter.responseAvailable (*iter)) { std::string lower = Misc::StringUtils::lowerCase(iter->mId); mActorKnownTopics.push_back (lower); @@ -412,7 +413,7 @@ namespace MWDialogue { Filter filter (mActor, mChoice, mTalkedTo); - if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic])) + if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true)) { mChoiceMap.clear(); mChoice = -1; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index d515c3ac42..5d56e94b09 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -554,7 +554,7 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) {} -const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const +const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const { bool infoRefusal = false; @@ -571,7 +571,7 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) } } - if (infoRefusal) + if (infoRefusal && fallbackToInfoRefusal) { // No response is valid because of low NPC disposition, // search a response in the topic "Info Refusal" @@ -590,3 +590,14 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) return 0; } +bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const +{ + for (std::vector::const_iterator iter = dialogue.mInfo.begin(); + iter!=dialogue.mInfo.end(); ++iter) + { + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) + return true; + } + + return false; +} diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index aa8934bfc4..707c0154b6 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -51,7 +51,12 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const; + const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; + ///< Get a matching response for the requested dialogue. + /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. + + bool responseAvailable (const ESM::Dialogue& dialogue) const; + ///< Does a matching response exist? (disposition is ignored for this check) }; } From 736e4716131238669105001cadd10f0308cc1a98 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 20 Jan 2013 15:57:34 +0100 Subject: [PATCH 0142/1483] Print a fallback text when no topic response is found --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index a8e6a98c9d..f548c46f75 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -249,12 +249,12 @@ namespace MWDialogue const ESM::Dialogue& dialogue = *dialogues.find (topic); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + if (const ESM::DialInfo *info = filter.search (dialogue, true)) { parseText (info->mResponse); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - if (dialogue.mType==ESM::Dialogue::Persuasion) { std::string modifiedTopic = "s" + topic; @@ -278,6 +278,13 @@ namespace MWDialogue mLastTopic = topic; mLastDialogue = *info; } + else + { + // no response found, print a fallback text + win->addTitle (topic); + win->addText ("…"); + + } } void DialogueManager::updateTopics() From af9e126487704ccf69090e7f4851e2ea8828d2f1 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 19 Jan 2013 22:53:41 +0100 Subject: [PATCH 0143/1483] =?UTF-8?q?Add=20unicode=20number=20for=20ellips?= =?UTF-8?q?is=20(=E2=80=A6)=20to=20code=20range?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- files/mygui/openmw_font.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index 0383c99427..b1446fae14 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -11,6 +11,7 @@ + From 31c71c029d9bfb662b1661c0422d6e325682ff1f Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 17:01:30 +0000 Subject: [PATCH 0144/1483] objects with scripts attached, that are inside containers will behave correctly when the container is moved --- apps/openmw/mwworld/worldimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ee18e5d953..46c58ecabd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -685,6 +685,7 @@ namespace MWWorld { mWorldScene->removeObjectFromScene (ptr); mLocalScripts.remove (ptr); + removeContainerScripts (ptr); } } } @@ -698,6 +699,8 @@ namespace MWWorld CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; + + removeContainerScripts(ptr); if (*currCell != newCell) { @@ -725,6 +728,8 @@ namespace MWWorld MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + addContainerScripts(copy, &newCell); + mRendering->moveObjectToCell(copy, vec, currCell); if (MWWorld::Class::get(ptr).isActor()) @@ -1333,6 +1338,7 @@ namespace MWWorld if (!script.empty()) { mLocalScripts.add(script, dropped); } + addContainerScripts(dropped, &cell); } } From 713d324eeb6713d62436454619ca2c6614d48dc7 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 20 Jan 2013 19:07:33 +0100 Subject: [PATCH 0145/1483] - Minor code cleanup --- apps/openmw/mwrender/terrain.cpp | 2 +- apps/openmw/mwworld/cellstore.hpp | 5 ++++- apps/openmw/mwworld/esmstore.cpp | 5 ++--- components/esm/esmreader.hpp | 6 +++--- components/esm/loadland.cpp | 2 +- components/esm/loadland.hpp | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index eb5b07af40..676139cf58 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -143,7 +143,7 @@ namespace MWRender std::map indexes; initTerrainTextures(&terrainData, cellX, cellY, x * numTextures, y * numTextures, - numTextures, indexes, land->plugin); + numTextures, indexes, land->mPlugin); if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL) { diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2b25faa70f..cbaf56458c 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -98,7 +98,10 @@ namespace MWWorld /// A list of container references. These references do not track their mRefnumber. /// Otherwise, taking 1 of 20 instances of an object would produce multiple objects /// with the same reference. - // TODO: Check how Morrowind does this! Maybe auto-generate references on drop. + /// Unfortunately, this also means that we need a different STL container. + /// (cells use CellRefList, where refs can be located according to their refnumner, + /// which uses a map; container items do not make use of the refnumber, so we + /// can't use a map with refnumber keys.) template struct ContainerRefList { diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 38fadca9ea..1666ad823a 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -28,8 +28,8 @@ void ESMStore::load(ESM::ESMReader &esm) ESM::Dialogue *dialogue = 0; // Cache parent esX files by tracking their indices in the global list of - // all files/readers used by the engine. This will greaty help to accelerate - // parsing of reference IDs. + // all files/readers used by the engine. This will greaty accelerate + // refnumber mangling, as required for handling moved references. int index = ~0; const ESM::ESMReader::MasterList &masters = esm.getMasters(); std::vector *allPlugins = esm.getGlobalReaderList(); @@ -122,7 +122,6 @@ void ESMStore::load(ESM::ESMReader &esm) cout << *it << " "; cout << endl; */ - //setUp(); } void ESMStore::setUp() diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index df4c1919e8..ba7d6c3e0c 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -80,9 +80,9 @@ public: // 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; mCtx.index = index;} - const int getIndex() {return idx;} + int mIdx; + void setIndex(const int index) {mIdx = index; mCtx.index = index;} + const int getIndex() {return mIdx;} void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} std::vector *getGlobalReaderList() {return mGlobalReaderList;} diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index ecc25501f7..89b48c27d8 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -81,7 +81,7 @@ Land::~Land() void Land::load(ESMReader &esm) { mEsm = &esm; - plugin = mEsm->getIndex(); + mPlugin = mEsm->getIndex(); // Get the grid location esm.getSubNameIs("INTV"); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index f72d020ac4..c1cce5e7ee 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -23,7 +23,7 @@ struct Land int mFlags; // Only first four bits seem to be used, don't know what // they mean. int mX, mY; // Map coordinates. - int plugin; // Plugin index, used to reference the correct material palette. + int mPlugin; // 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. From e1e76bde76fd441f867d20d412c9bfd2e53808aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 15:39:43 -0800 Subject: [PATCH 0146/1483] Combine a loop into another where it's used --- apps/openmw/mwrender/animation.cpp | 38 ++++++++++++++---------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 67be0bf0c5..4884712c3a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -67,34 +67,32 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { - Ogre::Bone *bone = boneiter.peekNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); - if(!data.isEmpty()) - { - mTextKeys["all"] = Ogre::any_cast(data); + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty()) + continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); - mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mTextKeys["all"] = Ogre::any_cast(data); - mStartPosition = mNonAccumRoot->getPosition(); - mLastPosition = mStartPosition; - break; - } - boneiter.moveNext(); - } + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); + mNonAccumRoot = skelinst->getBone(bone->getHandle()); + + mStartPosition = mNonAccumRoot->getPosition(); + mLastPosition = mStartPosition; - if(boneiter.hasMoreElements()) - { asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { Ogre::AnimationState *state = asiter.getNext(); - Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+"@"+state->getAnimationName()); - if(!data.isEmpty()) - mTextKeys[state->getAnimationName()] = Ogre::any_cast(data); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+state->getAnimationName()); + if(!groupdata.isEmpty()) + mTextKeys[state->getAnimationName()] = Ogre::any_cast(groupdata); } + + break; } } } From 536f8104e687d04d38fcee4c1f7b9b3218d56630 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 17:24:43 -0800 Subject: [PATCH 0147/1483] Do not create an 'all' animation. --- apps/openmw/mwrender/animation.cpp | 4 +--- components/nifogre/ogre_nif_loader.cpp | 29 ++++++++------------------ 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4884712c3a..75a441a9c9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -70,11 +70,9 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Bone *bone = boneiter.getNext(); Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty()) + if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mTextKeys["all"] = Ogre::any_cast(data); - mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 372c38e0fd..357866c7c2 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -308,7 +308,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, Ogre::Bone *&nonaccum, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { if(node->recType == Nif::RC_NiTriShape) return; @@ -341,7 +341,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorrecType == Nif::RC_NiTextKeyExtraData) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(extractTextKeys(tk))); + textkeys = extractTextKeys(tk); + nonaccum = bone; } e = e->extra; } @@ -353,7 +354,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector(nif.getRecord(0)); std::vector ctrls; + Ogre::Bone *nonaccum = NULL; + TextKeyMap textkeys; try { - buildBones(skel, node, ctrls); + buildBones(skel, node, nonaccum, textkeys, ctrls); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() <getBoneIterator(); - while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.peekNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(sTextKeyExtraDataID); - if(!data.isEmpty()) - { - textkeys = Ogre::any_cast(data); - break; - } - boneiter.moveNext(); - } - - buildAnimation(skel, "all", ctrls, targets, 0.0f, maxtime); + Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); + bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); @@ -459,7 +449,6 @@ void loadResource(Ogre::Resource *resource) groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); } while(insiter++ != lastkeyiter); - Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 8e8900e4221d015aa10f69344584f139dc00a86f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 22:51:39 -0800 Subject: [PATCH 0148/1483] Use the first bone with text keys as the nonaccum root. --- components/nifogre/ogre_nif_loader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 357866c7c2..890dcf7e98 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -320,8 +320,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc bone = skel->createBone(); if(parent) parent->addChild(bone); - if(!node->boneTrafo) - bone->setManuallyControlled(true); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); bone->setScale(Ogre::Vector3(node->trafo.scale)); @@ -338,7 +336,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiTextKeyExtraData) + if(e->recType == Nif::RC_NiTextKeyExtraData && !nonaccum) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); From 6905bd18ba09abc64a3a9b157d9309a36fd34d17 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 02:59:12 -0800 Subject: [PATCH 0149/1483] Filter out the group name from the text keys It's already in the animation name, and the text keys are animation-specific anyway. --- apps/openmw/mwmechanics/character.cpp | 10 ++-------- components/nifogre/ogre_nif_loader.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea934a2841..bc065d9d6a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -103,14 +103,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) // to this actor type return; } - std::string::size_type ms = mCurrentGroup.length()+2; - if(evt.length() <= ms || evt.compare(0, ms-2, mCurrentGroup) != 0 || evt.compare(ms-2, 2, ": ") != 0) - { - std::cerr<< "Event \""<first - keyiter->first, insiter->second)); + sep = insiter->second.find(':'); + if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, + insiter->second.substr(sep+2))); + else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); } while(insiter++ != lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); From e956a1cbc0e9c28aef893cedde957dc41c744f5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 03:24:52 -0800 Subject: [PATCH 0150/1483] Merge SpecialIdle character state into Idle --- apps/openmw/mwmechanics/character.cpp | 19 +++++++------------ apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bc065d9d6a..d0cbf04776 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -36,8 +36,7 @@ static const struct { const char groupname[32]; Ogre::Vector3 accumulate; } sStateList[] = { - { CharState_SpecialIdle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle, "idle", Ogre::Vector3::ZERO }, + { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, @@ -163,8 +162,7 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_SpecialIdle || getState() == CharState_Idle || - getState() == CharState_Dead)) + if(!(getState() == CharState_Idle || getState() == CharState_Dead)) { movement = mDirection * movement.length(); } @@ -175,7 +173,9 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - if(mAnimation && mAnimation->hasAnimation(groupname)) + if(!mAnimation || !mAnimation->hasAnimation(groupname)) + std::cerr<< "Animation "< 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; - mState = CharState_SpecialIdle; + mState = CharState_Idle; mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); @@ -207,12 +207,7 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) - { - // If setting the same state again, only reset the animation if looping - // is being turned on. - if(mLoop == loop || !(mLoop=loop)) - return; - } + return; else { mState = state; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 43ff21dfb2..ec9102f9f6 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -14,7 +14,6 @@ namespace MWMechanics { enum CharacterState { - CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, CharState_WalkForward, From f5f3c2e62d167943cc4542e9400067c246137291 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Mon, 21 Jan 2013 20:06:08 +0000 Subject: [PATCH 0151/1483] enabling / disabling should not affect scripts --- apps/openmw/mwworld/worldimp.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 46c58ecabd..24d139b377 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -427,8 +427,6 @@ namespace MWWorld { reference.getRefData().enable(); - addContainerScripts(reference, reference.getCell()); - if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); } @@ -459,10 +457,6 @@ namespace MWWorld { reference.getRefData().disable(); - removeContainerScripts(reference); - if(MWWorld::Class::get(reference).getScript(reference) != "") - mLocalScripts.remove(reference); - if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); } From 37fe1bd3f0f6e254501dca6c644bc2f69cac7c3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 22:51:13 -0800 Subject: [PATCH 0152/1483] Handle looping in the Animation object --- apps/openmw/mwmechanics/character.cpp | 44 ++++++----------------- apps/openmw/mwmechanics/character.hpp | 1 - apps/openmw/mwrender/animation.cpp | 31 +++++++++++++++- apps/openmw/mwrender/animation.hpp | 4 ++- apps/openmw/mwrender/characterpreview.cpp | 2 +- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d0cbf04776..83326d25af 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -61,8 +61,9 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(state)); } + CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) { if(!mAnimation) return; @@ -73,13 +74,13 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim getStateInfo(mState, &mCurrentGroup, &accum); mAnimation->setAccumulation(accum); if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop"); + mAnimation->play(mCurrentGroup, "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim), mLoop(rhs.mLoop) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(!mAnimation) return; @@ -103,32 +104,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) return; } - if(evt == "loop stop") - { - if(mAnimQueue.size() == 0) - { - if(time > 0.0f && mLoop) - mAnimation->play(mCurrentGroup, "loop start"); - } - else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start"); - } - return; - } - if(evt == "stop") { - if(mAnimQueue.size() == 0) - { - if(time > 0.0f && mLoop) - mAnimation->play(mCurrentGroup, "loop start"); - } - else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start"); + mAnimation->play(mCurrentGroup, "loop start", false); } else if(mAnimQueue.size() > 0) { @@ -136,7 +117,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start"); + mAnimation->play(mCurrentGroup, "start", false); } } return; @@ -185,9 +166,8 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_Idle; - mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) { @@ -208,11 +188,7 @@ void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) return; - else - { - mState = state; - mLoop = loop; - } + mState = state; if(!mAnimation) return; @@ -225,7 +201,7 @@ void CharacterController::setState(CharacterState state, bool loop) { mCurrentGroup = anim; mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "start"); + mAnimation->play(mCurrentGroup, "start", loop); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index ec9102f9f6..53349c841e 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -37,7 +37,6 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; - bool mLoop; protected: /* Called by the animation whenever a new text key is reached. */ diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 75a441a9c9..45f7ab2e44 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -173,7 +174,7 @@ float Animation::findStart(const std::string &groupname, const std::string &star } -void Animation::play(const std::string &groupname, const std::string &start) +void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { if(mAnimState) @@ -181,6 +182,7 @@ void Animation::play(const std::string &groupname, const std::string &start) mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); mCurrentKeys = &mTextKeys[groupname]; + mLooping = loop; resetPosition(findStart(groupname, start)); } @@ -209,6 +211,33 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) movement += updatePosition(time); timepassed = targetTime - time; + if(evt == "start" || evt == "loop start") + { + /* Do nothing */ + continue; + } + if(evt == "loop stop") + { + if(mLooping) + { + resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + if(mAnimState->getTimePosition() >= time) + break; + } + continue; + } + if(evt == "stop") + { + if(mLooping) + { + resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + if(mAnimState->getTimePosition() >= time) + break; + } + else if(mController) + mController->markerEvent(time, evt); + continue; + } if(mController) mController->markerEvent(time, evt); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 50ddc34d5c..8398135764 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,8 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + bool mLooping; + float mAnimSpeedMult; /* Updates the animation to the specified time, and returns the movement @@ -59,7 +61,7 @@ public: void setSpeedMult(float speedmult) { mAnimSpeedMult = speedmult; } - void play(const std::string &groupname, const std::string &start); + void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index cbee9c8659..5a1a93311b 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -144,7 +144,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->play("inventoryhandtohand", "start"); + mAnimation->play("inventoryhandtohand", "start", false); } // -------------------------------------------------------------------------------------------------- From d836b3d0ffbd9085bf06724b0aa59967982d627e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Jan 2013 00:24:57 -0800 Subject: [PATCH 0153/1483] Don't try to create animations if there's no text keys and nonaccum node. Such meshes apparently use NiBSAnimationNode, a Bethesda-specific extension which has animation-related info in its flags (values currently unknown). --- components/nifogre/ogre_nif_loader.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 4ae9c79f35..adc05f7e7f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -414,6 +414,13 @@ void loadResource(Ogre::Resource *resource) return; } + if(!nonaccum) + { + warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ + skel->getName()+", but no text keys. Uses NiBSAnimationNode?"); + return; + } + Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); From 05f8b8c28383dd21eb60d1042a0ba353c6503830 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Jan 2013 00:31:45 -0800 Subject: [PATCH 0154/1483] Specify the text key to reset animations to --- apps/openmw/mwrender/animation.cpp | 45 ++++++++++-------------------- apps/openmw/mwrender/animation.hpp | 6 ++-- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 45f7ab2e44..5a5761faa3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -134,14 +134,20 @@ Ogre::Vector3 Animation::updatePosition(float time) return posdiff; } -void Animation::resetPosition(float time) +void Animation::reset(const std::string &marker) { - mAnimState->setTimePosition(time); - mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) + while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; + if(mNextKey != mCurrentKeys->end()) + mAnimState->setTimePosition(mNextKey->first); + else + { + mNextKey = mCurrentKeys->begin(); + mAnimState->setTimePosition(0.0f); + } + if(mNonAccumRoot) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); @@ -151,29 +157,6 @@ void Animation::resetPosition(float time) } -float Animation::findStart(const std::string &groupname, const std::string &start) -{ - mNextKey = mCurrentKeys->end(); - if(mCurrentKeys->size() == 0) - return 0.0f; - - if(groupname == "all") - { - mNextKey = mCurrentKeys->begin(); - return 0.0f; - } - - std::string startmarker = groupname+": "+start; - NifOgre::TextKeyMap::const_iterator iter; - for(iter = mCurrentKeys->begin();iter != mCurrentKeys->end();iter++) - { - if(iter->second == startmarker) - return iter->first; - } - return 0.0f; -} - - void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { @@ -181,10 +164,10 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); + mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; - - resetPosition(findStart(groupname, start)); + reset(start); } catch(std::exception &e) { std::cerr<< e.what() <getAnimationName(), "loop start")); + reset("loop start"); if(mAnimState->getTimePosition() >= time) break; } @@ -230,7 +213,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + reset("loop start"); if(mAnimState->getTimePosition() >= time) break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 8398135764..ed9c6eb192 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,10 +38,10 @@ protected: /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Updates the animation to the specified time, without moving anything. */ - void resetPosition(float time); - float findStart(const std::string &groupname, const std::string &start); + /* Resets the animation to the time of the specified marker, without moving + * anything. If the marker is not found, it resets to the beginning. */ + void reset(const std::string &marker); void createEntityList(Ogre::SceneNode *node, const std::string &model); From 90d05858efe026d1b08252303f9c6b3534eeaa06 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 22 Jan 2013 11:50:08 +0100 Subject: [PATCH 0155/1483] disabling dialogue sub-views for now --- apps/opencs/view/world/tablesubview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index bb4bb76c61..f4deceb490 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -21,5 +21,6 @@ void CSVWorld::TableSubView::setEditLock (bool locked) void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) { - focusId (mTable->getUniversalId (index.row())); + /// \todo re-enable, after dialogue sub views have been fixed up +// focusId (mTable->getUniversalId (index.row())); } \ No newline at end of file From cac68c9e87fe50eb8b28644ecfcead4c3ca3f548 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 Jan 2013 11:48:47 +0100 Subject: [PATCH 0156/1483] Removed an outdated section from CMakeLists --- CMakeLists.txt | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 208d348fbe..2313d2d958 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,35 +67,6 @@ endif() # We probably support older versions than this. cmake_minimum_required(VERSION 2.6) -# -# Pre-built binaries being used? -# -IF(EXISTS "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd/ogre_1_7_1") - set(PREBUILT_DIR "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd") - message (STATUS "OpenMW pre-built binaries found at ${PREBUILT_DIR}.") - - SET(ENV{OGRE_HOME} "${PREBUILT_DIR}/ogre_1_7_1") - - SET(ENV{BOOST_ROOT} "${PREBUILT_DIR}/boost_1_42_0") - set(Boost_USE_STATIC_LIBS ON) - set(Boost_USE_MULTITHREADED ON) - set(ENV{BOOST_INCLUDEDIR} "${BOOST_ROOT}/include") - set(ENV{BOOST_LIBRARYDIR} "${BOOST_ROOT}/lib") - - set(ENV{FREETYPE_DIR} "${PREBUILT_DIR}/freetype-2.3.5-1") - - set(USE_MPG123 OFF) - set(USE_AUDIERE ON) - set(AUDIERE_INCLUDE_DIR "${PREBUILT_DIR}/audiere-1.9.4/include") - set(AUDIERE_LIBRARY "${PREBUILT_DIR}/audiere-1.9.4/lib/audiere.lib") - - set(ENV{OPENALDIR} "${PREBUILT_DIR}/OpenAL 1.1 SDK") - - set(BULLET_ROOT "${PREBUILT_DIR}/bullet") -ELSE() - message (STATUS "OpenMW pre-built binaries not found. Using standard locations.") -ENDIF() - # source directory: libs set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) From ed9a9904b431bb27ed9725e7c83023cf5fd11bab Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 24 Jan 2013 19:39:31 +0100 Subject: [PATCH 0157/1483] Dialogue filter: search script variables case-insensitively --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 5d56e94b09..c1542515a0 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -169,7 +169,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c int i = 0; for (; i (script->mVarNames.size()); ++i) - if (script->mVarNames[i]==name) + if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name) break; if (i>=static_cast (script->mVarNames.size())) From 19dff822f4f963fdab88d5f8f80c9b026edd6f91 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 24 Jan 2013 19:43:21 +0100 Subject: [PATCH 0158/1483] Dialogue: do not filter on disposition for creatures --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index c1542515a0..09bb0ddc4c 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -123,6 +123,11 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const { + bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); + + if (isCreature) + return true; + int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); return actorDisposition >= info.mData.mDisposition; From 6faf6f57e1c64870f8bd954679fb16352d2219f4 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Fri, 25 Jan 2013 05:19:06 +0100 Subject: [PATCH 0159/1483] Added settings file reader/writers for openmw.cfg and settings.cfg --- apps/launcher/CMakeLists.txt | 7 ++ apps/launcher/settings/gamesettings.cpp | 34 ++++++++ apps/launcher/settings/gamesettings.hpp | 15 ++++ apps/launcher/settings/graphicssettings.cpp | 46 +++++++++++ apps/launcher/settings/graphicssettings.hpp | 16 ++++ apps/launcher/settings/settingsbase.hpp | 88 +++++++++++++++++++++ 6 files changed, 206 insertions(+) create mode 100644 apps/launcher/settings/gamesettings.cpp create mode 100644 apps/launcher/settings/gamesettings.hpp create mode 100644 apps/launcher/settings/graphicssettings.cpp create mode 100644 apps/launcher/settings/graphicssettings.hpp create mode 100644 apps/launcher/settings/settingsbase.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 09beaf59de..2895b6345f 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -9,6 +9,9 @@ set(LAUNCHER model/modelitem.cpp model/esm/esmfile.cpp + settings/gamesettings.cpp + settings/graphicssettings.cpp + utils/filedialog.cpp utils/naturalsort.cpp utils/lineedit.cpp @@ -28,6 +31,10 @@ set(LAUNCHER_HEADER model/modelitem.hpp model/esm/esmfile.hpp + settings/gamesettings.hpp + settings/graphicssettings.hpp + settings/settingsbase.hpp + utils/lineedit.hpp utils/filedialog.hpp utils/naturalsort.hpp diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp new file mode 100644 index 0000000000..32f03ddbe3 --- /dev/null +++ b/apps/launcher/settings/gamesettings.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#include + +#include "gamesettings.hpp" + +GameSettings::GameSettings() +{ +} + +GameSettings::~GameSettings() +{ +} + +bool GameSettings::writeFile(QTextStream &stream) +{ + QMap settings = SettingsBase::getSettings(); + + QMapIterator i(settings); + while (i.hasNext()) { + i.next(); + + // Quote values with spaces + if (i.value().contains(" ")) { + stream << i.key() << "=\"" << i.value() << "\"\n"; + } else { + stream << i.key() << "=" << i.value() << "\n"; + } + + } +} diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp new file mode 100644 index 0000000000..c81c67d978 --- /dev/null +++ b/apps/launcher/settings/gamesettings.hpp @@ -0,0 +1,15 @@ +#ifndef GAMESETTINGS_HPP +#define GAMESETTINGS_HPP + +#include "settingsbase.hpp" + +class GameSettings : public SettingsBase> +{ +public: + GameSettings(); + ~GameSettings(); + + bool writeFile(QTextStream &stream); +}; + +#endif // GAMESETTINGS_HPP diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp new file mode 100644 index 0000000000..fd70917b5d --- /dev/null +++ b/apps/launcher/settings/graphicssettings.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +#include + +#include "graphicssettings.hpp" + +GraphicsSettings::GraphicsSettings() +{ +} + +GraphicsSettings::~GraphicsSettings() +{ +} + +bool GraphicsSettings::writeFile(QTextStream &stream) +{ + QString sectionPrefix; + QRegExp sectionRe("([^/]+)/(.+)$"); + QMap settings = SettingsBase::getSettings(); + + QMapIterator i(settings); + while (i.hasNext()) { + i.next(); + + QString prefix; + QString key; + + if (sectionRe.exactMatch(i.key())) { + prefix = sectionRe.cap(1); + key = sectionRe.cap(2); + } + + if (sectionPrefix != prefix) { + sectionPrefix = prefix; + stream << "\n[" << prefix << "]\n"; + } + + stream << key << " = " << i.value() << "\n"; + } + + return true; + +} diff --git a/apps/launcher/settings/graphicssettings.hpp b/apps/launcher/settings/graphicssettings.hpp new file mode 100644 index 0000000000..8c690ebc5f --- /dev/null +++ b/apps/launcher/settings/graphicssettings.hpp @@ -0,0 +1,16 @@ +#ifndef GRAPHICSSETTINGS_HPP +#define GRAPHICSSETTINGS_HPP + +#include "settingsbase.hpp" + +class GraphicsSettings : public SettingsBase> +{ +public: + GraphicsSettings(); + ~GraphicsSettings(); + + bool writeFile(QTextStream &stream); + +}; + +#endif // GRAPHICSSETTINGS_HPP diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp new file mode 100644 index 0000000000..6b8b52762d --- /dev/null +++ b/apps/launcher/settings/settingsbase.hpp @@ -0,0 +1,88 @@ +#ifndef SETTINGSBASE_HPP +#define SETTINGSBASE_HPP + +#include +#include +#include +#include + +#include + +template +class SettingsBase +{ + +public: + SettingsBase() {} + ~SettingsBase() {} + + inline QString value(const QString &key, const QString &defaultValue = QString()) + { + return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key); + } + + inline void setValue(const QString &key, const QString &value) + { + mSettings.insert(key, value); + } + + Map getSettings() {return mSettings;} + + bool readFile(QTextStream &stream) + { + mCache.clear(); + + QString sectionPrefix; + QRegExp sectionRe("^\\[([^]]+)\\]"); + QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); + + while (!stream.atEnd()) { + QString line = stream.readLine().simplified(); + + if (line.isEmpty() || line.startsWith("#")) + continue; + + if (sectionRe.exactMatch(line)) { + sectionPrefix = sectionRe.cap(1); + sectionPrefix.append("/"); + continue; + } + + if (keyRe.indexIn(line) != -1) { + + QString key = keyRe.cap(1).simplified(); + QString value = keyRe.cap(2).simplified(); + + if (!sectionPrefix.isEmpty()) + key.prepend(sectionPrefix); + + // QMap will replace the value if key exists, QMultiMap creates a new one + mCache.insert(key, value); + } + } + + if (mSettings.isEmpty()) { + mSettings = mCache; // This is the first time we read a file + return true; + } + + // Replace values from previous settings + QMapIterator i(mCache); + while (i.hasNext()) { + i.next(); + if (mSettings.contains(i.key())) + mSettings.remove(i.key()); + } + + // Merge the changed keys with those which didn't + mSettings.unite(mCache); + qDebug() << mSettings; + return true; + } + +private: + Map mSettings; + Map mCache; +}; + +#endif // SETTINGSBASE_HPP From 854eff321f3992d8da6e324577d130df0d3e1f7d Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Fri, 25 Jan 2013 17:54:05 +0100 Subject: [PATCH 0160/1483] - Some time ago, upstream/master did merge the submodule 'shiny' into upstream/master. This branch now does this as well. --- extern/shiny | 1 - extern/shiny/CMakeLists.txt | 75 + extern/shiny/Docs/Configurations.dox | 32 + extern/shiny/Docs/Doxyfile | 1826 ++++ extern/shiny/Docs/GettingStarted.dox | 65 + extern/shiny/Docs/Lod.dox | 49 + extern/shiny/Docs/Macros.dox | 270 + extern/shiny/Docs/Mainpage.dox | 13 + extern/shiny/Docs/Materials.dox | 128 + extern/shiny/Extra/core.h | 168 + extern/shiny/License.txt | 9 + extern/shiny/Main/Factory.cpp | 583 ++ extern/shiny/Main/Factory.hpp | 207 + extern/shiny/Main/Language.hpp | 16 + extern/shiny/Main/MaterialInstance.cpp | 220 + extern/shiny/Main/MaterialInstance.hpp | 104 + extern/shiny/Main/MaterialInstancePass.cpp | 16 + extern/shiny/Main/MaterialInstancePass.hpp | 29 + .../Main/MaterialInstanceTextureUnit.cpp | 14 + .../Main/MaterialInstanceTextureUnit.hpp | 26 + extern/shiny/Main/Platform.cpp | 94 + extern/shiny/Main/Platform.hpp | 145 + extern/shiny/Main/Preprocessor.cpp | 99 + extern/shiny/Main/Preprocessor.hpp | 69 + extern/shiny/Main/PropertyBase.cpp | 268 + extern/shiny/Main/PropertyBase.hpp | 235 + extern/shiny/Main/ScriptLoader.cpp | 401 + extern/shiny/Main/ScriptLoader.hpp | 134 + extern/shiny/Main/ShaderInstance.cpp | 707 ++ extern/shiny/Main/ShaderInstance.hpp | 71 + extern/shiny/Main/ShaderSet.cpp | 172 + extern/shiny/Main/ShaderSet.hpp | 71 + .../shiny/Platforms/Ogre/OgreGpuProgram.cpp | 70 + .../shiny/Platforms/Ogre/OgreGpuProgram.hpp | 31 + extern/shiny/Platforms/Ogre/OgreMaterial.cpp | 99 + extern/shiny/Platforms/Ogre/OgreMaterial.hpp | 38 + .../Platforms/Ogre/OgreMaterialSerializer.cpp | 67 + .../Platforms/Ogre/OgreMaterialSerializer.hpp | 29 + extern/shiny/Platforms/Ogre/OgrePass.cpp | 128 + extern/shiny/Platforms/Ogre/OgrePass.hpp | 35 + extern/shiny/Platforms/Ogre/OgrePlatform.cpp | 174 + extern/shiny/Platforms/Ogre/OgrePlatform.hpp | 72 + .../Platforms/Ogre/OgreTextureUnitState.cpp | 40 + .../Platforms/Ogre/OgreTextureUnitState.hpp | 27 + extern/shiny/Preprocessor/aq.cpp | 236 + extern/shiny/Preprocessor/cpp_re.cpp | 442 + extern/shiny/Preprocessor/cpp_re.inc | 9044 +++++++++++++++++ .../instantiate_cpp_exprgrammar.cpp | 52 + .../Preprocessor/instantiate_cpp_grammar.cpp | 56 + .../instantiate_cpp_literalgrs.cpp | 56 + .../instantiate_defined_grammar.cpp | 52 + .../instantiate_predef_macros.cpp | 52 + .../Preprocessor/instantiate_re2c_lexer.cpp | 65 + .../instantiate_re2c_lexer_str.cpp | 64 + extern/shiny/Preprocessor/token_ids.cpp | 447 + extern/shiny/Readme.txt | 33 + 56 files changed, 17725 insertions(+), 1 deletion(-) delete mode 160000 extern/shiny create mode 100644 extern/shiny/CMakeLists.txt create mode 100644 extern/shiny/Docs/Configurations.dox create mode 100644 extern/shiny/Docs/Doxyfile create mode 100644 extern/shiny/Docs/GettingStarted.dox create mode 100644 extern/shiny/Docs/Lod.dox create mode 100644 extern/shiny/Docs/Macros.dox create mode 100644 extern/shiny/Docs/Mainpage.dox create mode 100644 extern/shiny/Docs/Materials.dox create mode 100644 extern/shiny/Extra/core.h create mode 100644 extern/shiny/License.txt create mode 100644 extern/shiny/Main/Factory.cpp create mode 100644 extern/shiny/Main/Factory.hpp create mode 100644 extern/shiny/Main/Language.hpp create mode 100644 extern/shiny/Main/MaterialInstance.cpp create mode 100644 extern/shiny/Main/MaterialInstance.hpp create mode 100644 extern/shiny/Main/MaterialInstancePass.cpp create mode 100644 extern/shiny/Main/MaterialInstancePass.hpp create mode 100644 extern/shiny/Main/MaterialInstanceTextureUnit.cpp create mode 100644 extern/shiny/Main/MaterialInstanceTextureUnit.hpp create mode 100644 extern/shiny/Main/Platform.cpp create mode 100644 extern/shiny/Main/Platform.hpp create mode 100644 extern/shiny/Main/Preprocessor.cpp create mode 100644 extern/shiny/Main/Preprocessor.hpp create mode 100644 extern/shiny/Main/PropertyBase.cpp create mode 100644 extern/shiny/Main/PropertyBase.hpp create mode 100644 extern/shiny/Main/ScriptLoader.cpp create mode 100644 extern/shiny/Main/ScriptLoader.hpp create mode 100644 extern/shiny/Main/ShaderInstance.cpp create mode 100644 extern/shiny/Main/ShaderInstance.hpp create mode 100644 extern/shiny/Main/ShaderSet.cpp create mode 100644 extern/shiny/Main/ShaderSet.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgreMaterial.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgreMaterial.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgrePass.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgrePass.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgrePlatform.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgrePlatform.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp create mode 100644 extern/shiny/Preprocessor/aq.cpp create mode 100644 extern/shiny/Preprocessor/cpp_re.cpp create mode 100644 extern/shiny/Preprocessor/cpp_re.inc create mode 100644 extern/shiny/Preprocessor/instantiate_cpp_exprgrammar.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_cpp_grammar.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_cpp_literalgrs.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_defined_grammar.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_predef_macros.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_re2c_lexer.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_re2c_lexer_str.cpp create mode 100644 extern/shiny/Preprocessor/token_ids.cpp create mode 100644 extern/shiny/Readme.txt diff --git a/extern/shiny b/extern/shiny deleted file mode 160000 index 4750676ac4..0000000000 --- a/extern/shiny +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4750676ac46a7aaa86bca53dc68c5a1ba11f3bc1 diff --git a/extern/shiny/CMakeLists.txt b/extern/shiny/CMakeLists.txt new file mode 100644 index 0000000000..603336413e --- /dev/null +++ b/extern/shiny/CMakeLists.txt @@ -0,0 +1,75 @@ +cmake_minimum_required(VERSION 2.8) + +# This is NOT intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project. +# Make sure to link against Ogre and boost::filesystem. + +option(SHINY_BUILD_OGRE_PLATFORM "build the Ogre platform" ON) + +set(SHINY_LIBRARY "shiny") +set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform") + +# Sources +file(GLOB SOURCE_FILES Main/*.cpp ) + +set(SOURCE_FILES + Main/Factory.cpp + Main/MaterialInstance.cpp + Main/MaterialInstancePass.cpp + Main/MaterialInstanceTextureUnit.cpp + Main/Platform.cpp + Main/Preprocessor.cpp + Main/PropertyBase.cpp + Main/ScriptLoader.cpp + Main/ShaderInstance.cpp + Main/ShaderSet.cpp +) + +# In Debug mode, write the shader sources to the current directory +if (DEFINED CMAKE_BUILD_TYPE) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DSHINY_WRITE_SHADER_DEBUG) + endif() +endif() + +if (DEFINED SHINY_USE_WAVE_SYSTEM_INSTALL) + # use system install +else() + list(APPEND SOURCE_FILES + Preprocessor/aq.cpp + Preprocessor/cpp_re.cpp + Preprocessor/instantiate_cpp_literalgrs.cpp + Preprocessor/instantiate_cpp_exprgrammar.cpp + Preprocessor/instantiate_cpp_grammar.cpp + Preprocessor/instantiate_defined_grammar.cpp + Preprocessor/instantiate_predef_macros.cpp + Preprocessor/instantiate_re2c_lexer.cpp + Preprocessor/instantiate_re2c_lexer_str.cpp + Preprocessor/token_ids.cpp + ) + + # Don't use thread-safe boost::wave. Results in a huge speed-up for the preprocessor. + add_definitions(-DBOOST_WAVE_SUPPORT_THREADING=0) +endif() + +set(OGRE_PLATFORM_SOURCE_FILES + Platforms/Ogre/OgreGpuProgram.cpp + Platforms/Ogre/OgreMaterial.cpp + Platforms/Ogre/OgreMaterialSerializer.cpp + Platforms/Ogre/OgrePass.cpp + Platforms/Ogre/OgrePlatform.cpp + Platforms/Ogre/OgreTextureUnitState.cpp +) + +file(GLOB OGRE_PLATFORM_SOURCE_FILES Platforms/Ogre/*.cpp) + +add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES}) + +if (SHINY_BUILD_OGRE_PLATFORM) + add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES}) +endif() + + +link_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE) +set(SHINY_OGREPLATFORM_LIBRARY ${SHINY_OGREPLATFORM_LIBRARY} PARENT_SCOPE) diff --git a/extern/shiny/Docs/Configurations.dox b/extern/shiny/Docs/Configurations.dox new file mode 100644 index 0000000000..affd914237 --- /dev/null +++ b/extern/shiny/Docs/Configurations.dox @@ -0,0 +1,32 @@ +/*! + + \page configurations Configurations + + A common task in shader development is to provide a different set of simpler shaders for all your materials. Some examples: + - When rendering cubic or planar reflection maps in real-time, you will want to disable shadows. + - For an in-game minimap render target, you don't want to have fog. + + For this task, the library provides a \a Configuration concept. + + A Configuration is a set of properties that can override global settings, as long as this Configuration is active. + + Here's an example. Say you have a global setting with the name 'shadows' that controls if your materials receive shadows. + + Now, lets create a configuration for our reflection render targets that disables shadows for all materials. Paste the following in a new file with the extension '.configuration': + + \code + configuration reflection_targets + { + shadows false + } + \endcode + + \note You may also create configurations using sh::Factory::registerConfiguration. + + The active Configuration is controlled by the active material scheme in Ogre. So, in order to use the configuration "reflection_targets" for your reflection renders, simply call + \code + viewport->setMaterialScheme ("reflection_targets"); + \endcode + on the Ogre viewport of your reflection render! + +*/ diff --git a/extern/shiny/Docs/Doxyfile b/extern/shiny/Docs/Doxyfile new file mode 100644 index 0000000000..3564c45f67 --- /dev/null +++ b/extern/shiny/Docs/Doxyfile @@ -0,0 +1,1826 @@ +# Doxyfile 1.8.1.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = shiny + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = /home/scrawl/sh_doxy/generated + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/extern/shiny/Docs/GettingStarted.dox b/extern/shiny/Docs/GettingStarted.dox new file mode 100644 index 0000000000..b9cf58e23a --- /dev/null +++ b/extern/shiny/Docs/GettingStarted.dox @@ -0,0 +1,65 @@ +/*! + \page getting-started Getting started + + \section download Download the source + + \code + git clone git@github.com:scrawl/shiny.git + \endcode + + \section building Build the source + + The source files you want to build are: + - Main/*.cpp + - Preprocessor/*.cpp (unless you are using the system install of boost::wave, more below) + - Platforms/Ogre/*.cpp + + You can either build the sources as a static library, or simply add the sources to the source tree of your project. + + If you use CMake, you might find the included CMakeLists.txt useful. It builds static libraries with the names "shiny" and "shiny.OgrePlatform". + + \note The CMakeLists.txt is not intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project. + + Make sure to link against OGRE and the boost filesystem library. + + If your boost version is older than 1.49, you must set the SHINY_USE_WAVE_SYSTEM_INSTALL variable and additionally link against the boost wave library. + + \code + set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE") + \endcode + + \section code Basic initialisation code + + Add the following code to your application: + + \code{cpp} + + #include + #include + + .... + + sh::OgrePlatform* platform = new sh::OgrePlatform( + "General", // OGRE Resource group to use for creating materials. + myApplication.getDataPath() + "/" + "materials" // Path to look for materials and shaders. NOTE: This does NOT use the Ogre resource system, so you have to specify an absolute path. + ); + + sh::Factory* factory = new sh::Factory(platform); + + // Set a language. Valid options: CG, HLSL, GLSL + factory->setCurrentLanguage(sh::Language_GLSL); + + factory->loadAllFiles(); + + .... + your application runs here + .... + + // don't forget to delete on exit + delete factory; + + \endcode + + That's it! Now you can start defining materials. Refer to the page \ref defining-materials-shaders . + +*/ diff --git a/extern/shiny/Docs/Lod.dox b/extern/shiny/Docs/Lod.dox new file mode 100644 index 0000000000..37d004638e --- /dev/null +++ b/extern/shiny/Docs/Lod.dox @@ -0,0 +1,49 @@ +/*! + + \page lod Material LOD + + \section howitworks How it works + + When Ogre requests a technique for a specific LOD index, the Factory selects the appropriate LOD configuration which then temporarily overrides the global settings in the shaders. We can use this to disable shader features one by one at a lower LOD, resulting in simpler and faster techniques for distant objects. + + \section howtouseit How to use it + + - Create a file with the extension '.lod'. There you can specify shader features to disable at a specific LOD level. Higher LOD index refers to a lower LOD. Example contents: + + \code + lod_configuration 1 + { + specular_mapping false + } + + lod_configuration 2 + { + specular_mapping false + normal_mapping false + } + + lod_configuration 3 + { + terrain_composite_map true + specular_mapping false + normal_mapping false + } + \endcode + + \note You can also add LOD configurations by calling \a sh::Factory::registerLodConfiguration. + + \note Do not use an index of 0. LOD 0 refers to the highest LOD, and you will never want to disable features at the highest LOD level. + + + - In your materials, specify the distances at which a lower LOD kicks in. Note that the actual distance might also be affected by the viewport and current entity LOD bias. In this example, the first LOD level (lod index 1) would normally be applied at a distance of 100 units, the next after 300, and the last after 1000 units. + + \code + material sample_material + { + lod_values 100 300 1000 + + ... your passes, texture units etc ... + } + \endcode + +*/ diff --git a/extern/shiny/Docs/Macros.dox b/extern/shiny/Docs/Macros.dox new file mode 100644 index 0000000000..0578c447f3 --- /dev/null +++ b/extern/shiny/Docs/Macros.dox @@ -0,0 +1,270 @@ +/*! + \page macros Shader Macros + + \tableofcontents + + \section Shader Language + + These macros are automatically defined, depending on the shader language that has been set by the application using sh::Factory::setCurrentLanguage. + + - SH_GLSL + - SH_HLSL + - SH_CG + + Example: + + \code + #if SH_GLSL == 1 + // glsl porting code + #endif + + #if SH_CG == 1 || SH_HLSL == 1 + // cg / hlsl porting code (similiar syntax) + #endif + \endcode + + \note It is encouraged to use the shipped porting header (extra/core.h) by #include-ing it in your shaders. If you do that, you should not have to use the above macros directly. + + \section vertex-fragment Vertex / fragment shader + + These macros are automatically defined, depending on the type of shader that is currently being compiled. + + - SH_VERTEX_SHADER + - SH_FRAGMENT_SHADER + + If you use the same source file for both vertex and fragment shader, then it is advised to use these macros for blending out the unused source. This will reduce your compile time. + + \section passthrough Vertex -> Fragment passthrough + + In shader development, a common task is to pass variables from the vertex to the fragment shader. This is no problem if you have a deterministic shader source (i.e. no #ifdefs). + + However, as soon as you begin to have lots of permutations of the same shader source, a problem arises. All current GPUs have a limit of 8 vertex to fragment passthroughs (with 4 components each, for example a float4). + + A common optimization is to put several individual float values together in a float4 (so-called "Packing"). But if your shader has lots of permutations and the passthrough elements you actually need are not known beforehand, it can be very tedious to pack manually. With the following macros, packing can become easier. + + \subsection shAllocatePassthrough shAllocatePassthrough + + Usage: \@shAllocatePassthrough(num_components, name) + + Example: + \code + #if FRAGMENT_NEED_DEPTH + @shAllocatePassthrough(1, depth) + #endif + \endcode + + This is the first thing you should do before using any of the macros below. + + \subsection shPassthroughVertexOutputs shPassthroughVertexOutputs + + Usage: \@shPassthroughVertexOutputs + + Use this in the inputs/outputs section of your vertex shader, in order to declare all the outputs that are needed for packing the variables that you want passed to the fragment. + + \subsection shPassthroughFragmentInputs shPassthroughFragmentInputs + + Usage: \@shPassthroughFragmentInputs + + Use this in the inputs/outputs section of your fragment shader, in order to declare all the inputs that are needed for receiving the variables that you want passed to the fragment. + + \subsection shPassthroughAssign shPassthroughAssign + + Usage: \@shPassthroughAssign(name, value) + + Use this in the vertex shader for assigning a value to the variable you want passed to the fragment. + + Example: + \code + #if FRAGMENT_NEED_DEPTH + @shPassthroughAssign(depth, shOutputPosition.z); + #endif + + \endcode + + \subsection shPassthroughReceive shPassthroughReceive + + Usage: \@shPassthroughReceive(name) + + Use this in the fragment shader to receive the passed value. + + Example: + + \code + #if FRAGMENT_NEED_DEPTH + float depth = @shPassthroughReceive(depth); + #endif + \endcode + + \section texUnits Texture units + + \subsection shUseSampler shUseSampler + + Usage: \@shUseSampler(samplerName) + + Requests the texture unit with name \a samplerName to be available for use in this pass. + + Why is this necessary? If you have a derived material that does not use all of the texture units that its parent defines (for example, if an optional asset such as a normal map is not available), there would be no way to know which texture units are actually needed and which can be skipped in the creation process (those that are never referenced in the shader). + + \section properties Property retrieval / binding + + \subsection shUniformProperty shUniformProperty + + Usage: \@shUniformProperty<4f|3f|2f|1f|int> (uniformName, property) + + Binds the value of \a property (from the shader_properties of the pass this shader belongs to) to the uniform with name \a uniformName. + + The following variants are available, depending on the type of your uniform variable: + - \@shUniformProperty4f + - \@shUniformProperty3f + - \@shUniformProperty2f + - \@shUniformProperty1f + - \@shUniformPropertyInt + + Example: \@shUniformProperty1f (uFresnelScale, fresnelScale) + + \subsection shPropertyBool shPropertyBool + + Retrieve a boolean property of the pass that this shader belongs to, gets replaced with either 0 or 1. + + Usage: \@shPropertyBool(propertyName) + + Example: + \code + #if @shPropertyBool(has_normal_map) + ... + #endif + \endcode + + \subsection shPropertyNotBool shPropertyNotBool + + Same as shPropertyBool, but inverts the result (i.e. when shPropertyBool would return 0, this returns 1 and vice versa) + + \subsection shPropertyString shPropertyString + + Retrieve a string property of the pass that this shader belongs to + + Usage: \@shPropertyString(propertyName) + + \subsection shPropertyEqual shPropertyEqual + + Check if the value of a property equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers. + + Usage: \@shPropertyEqual(propertyName, value) + + Example: + \code + #if @shPropertyEqual(lighting_mode, phong) + ... + #endif + \endcode + + \section globalSettings Global settings + + \subsection shGlobalSettingBool shGlobalSettingBool + + Retrieves the boolean value of a specific global setting, gets replaced with either 0 or 1. The value can be set using sh::Factory::setGlobalSetting. + + Usage: \@shGlobalSettingBool(settingName) + + \subsection shGlobalSettingEqual shGlobalSettingEqual + + Check if the value of a global setting equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers. + + Usage: \@shGlobalSettingEqual(settingName, value) + + \subsection shGlobalSettingString shGlobalSettingString + + Gets replaced with the current value of a given global setting. The value can be set using sh::Factory::setGlobalSetting. + + Usage: \@shGlobalSettingString(settingName) + + \section sharedParams Shared parameters + + \subsection shSharedParameter shSharedParameter + + Allows you to bind a custom value to a uniform parameter. + + Usage: \@shSharedParameter(sharedParameterName) + + Example: \@shSharedParameter(pssmSplitPoints) - now the uniform parameter 'pssmSplitPoints' can be altered in all shaders that use it by executing sh::Factory::setSharedParameter("pssmSplitPoints", value) + + \note You may use the same shared parameter in as many shaders as you want. But don't forget to add the \@shSharedParameter macro to every shader that uses this shared parameter. + + \section autoconstants Auto constants + + \subsection shAutoConstant shAutoConstant + + Usage: \@shAutoConstant(uniformName, autoConstantName, [extraData]) + + Example: \@shAutoConstant(uModelViewMatrix, worldviewproj_matrix) + + Example: \@shAutoConstant(uLightPosition4, light_position, 4) + + Binds auto constant with name \a autoConstantName to the uniform \a uniformName. Optionally, you may specify extra data (for example the light index), as required by some auto constants. + + The auto constant names are the same as Ogre's. Read the section "3.1.9 Using Vertex/Geometry/Fragment Programs in a Pass" of the Ogre manual for a list of all auto constant names. + + \section misc Misc + + \subsection shForeach shForeach + + Usage: \@shForeach(n) + + Repeats the content of this foreach block \a n times. The end of the block is marked via \@shEndForeach, and the current iteration number can be retrieved via \@shIterator. + + \note Nested foreach blocks are currently \a not supported. + + \note For technical reasons, you can only use constant numbers, properties (\@shPropertyString) or global settings (\@shGlobalSettingString) as \a n parameter. + + Example: + + \code + @shForeach(3) + this is iteration number @shIterator + @shEndForeach + + Gets replaced with: + + this is iteration number 0 + this is iteration number 1 + this is iteration number 2 + \endcode + + Optionally, you can pass a constant offset to \@shIterator. Example: + + \code + @shForeach(3) + this is iteration number @shIterator(7) + @shEndForeach + + Gets replaced with: + + this is iteration number 7 + this is iteration number 8 + this is iteration number 9 + \endcode + + \subsection shCounter shCounter + + Gets replaced after the preprocessing step with the number that equals the n-th occurence of counters of the same ID. + + Usage: \@shCounter(ID) + + Example: + \code + @shCounter(0) + @shCounter(0) + @shCounter(1) + @shCounter(0) + \endcode + + Gets replaced with: + + \code + 0 + 1 + 0 + 2 + \endcode + +*/ diff --git a/extern/shiny/Docs/Mainpage.dox b/extern/shiny/Docs/Mainpage.dox new file mode 100644 index 0000000000..fb8f596dc0 --- /dev/null +++ b/extern/shiny/Docs/Mainpage.dox @@ -0,0 +1,13 @@ +/*! + + \mainpage + + - \ref getting-started + - \ref defining-materials-shaders + - \ref macros + - \ref configurations + - \ref lod + + - sh::Factory - the main interface class + +*/ diff --git a/extern/shiny/Docs/Materials.dox b/extern/shiny/Docs/Materials.dox new file mode 100644 index 0000000000..2dae60560d --- /dev/null +++ b/extern/shiny/Docs/Materials.dox @@ -0,0 +1,128 @@ +/*! + + \page defining-materials-shaders Defining materials and shaders + + \section first-material Your first material + + Create a file called "myFirstMaterial.mat" and place it in the path you have used in your initialisation code (see \ref getting-started). Paste the following: + + \code + + material my_first_material + { + diffuse 1.0 1.0 1.0 1.0 + specular 0.4 0.4 0.4 32 + ambient 1.0 1.0 1.0 + emissive 0.0 0.0 0.0 + diffuseMap black.png + + pass + { + diffuse $diffuse + specular $specular + ambient $ambient + emissive $emissive + + texture_unit diffuseMap + { + texture $diffuseMap + create_in_ffp true // use this texture unit for fixed function pipeline + } + } + } + + material material1 + { + parent my_first_material + diffuseMap texture1.png + } + + material material2 + { + parent my_first_material + diffuseMap texture2.png + } + + \endcode + + \section first-shader The first shader + + Change the 'pass' section to include some shaders: + + \code + pass + { + vertex_program my_first_shader_vertex + fragment_program my_first_shader_fragment + ... + } + \endcode + + \note This does \a not refer to a single shader with a fixed source code, but in fact will automatically create a new \a instance of this shader (if necessary), which can have its own uniform variables, compile-time macros and much more! + + Next, we're going to define our shaders. Paste this in a new file called 'myfirstshader.shaderset' + + \code + shader_set my_first_shader_vertex + { + source example.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 + } + + shader_set my_first_shader_fragment + { + source example.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 + } + \endcode + + Some notes: + - There is no entry_point property because the entry point is always \a main. + - Both profiles_cg and profiles_hlsl are a list of shader profiles. The first profile that is supported is automatically picked. GLSL does not have shader profiles. + + Now, let's get into writing our shader! As you can guess from above, the filename should be 'example.shader' + + \code + #include "core.h" + + #ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shInput(float2, uv0) + shOutput(float2, UV) + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + } + + #else + + SH_BEGIN_PROGRAM + // NOTE: It is important that the sampler name here (diffuseMap) matches + // the name of the texture unit in the material. This is necessary because the system + // skips texture units that are never "referenced" in the shader. This can be the case + // when your base material has optional assets (for example a normal map) that are not + // used by some derived materials. + shSampler2D(diffuseMap) + shInput(float2, UV) + SH_START_PROGRAM + { + shOutputColour(0) = shSample(diffuseMap, UV); + } + + #endif + + \endcode + + There you have it! This shader will compile in several languages thanks to the porting defines in "core.h". If you need more defines, feel free to add them and don't forget to send them to me! + + For a full list of macros available when writing your shaders, refer to the page \ref macros + + In the future, some more in-depth shader examples might follow. +*/ diff --git a/extern/shiny/Extra/core.h b/extern/shiny/Extra/core.h new file mode 100644 index 0000000000..cba7167770 --- /dev/null +++ b/extern/shiny/Extra/core.h @@ -0,0 +1,168 @@ +#if SH_HLSL == 1 || SH_CG == 1 + + #define shTexture2D sampler2D + #define shSample(tex, coord) tex2D(tex, coord) + #define shCubicSample(tex, coord) texCUBE(tex, coord) + #define shLerp(a, b, t) lerp(a, b, t) + #define shSaturate(a) saturate(a) + + #define shSampler2D(name) , uniform sampler2D name : register(s@shCounter(0)) @shUseSampler(name) + + #define shSamplerCube(name) , uniform samplerCUBE name : register(s@shCounter(0)) @shUseSampler(name) + + #define shMatrixMult(m, v) mul(m, v) + + #define shUniform(type, name) , uniform type name + + #define shTangentInput(type) , in type tangent : TANGENT + #define shVertexInput(type, name) , in type name : TEXCOORD@shCounter(1) + #define shInput(type, name) , in type name : TEXCOORD@shCounter(1) + #define shOutput(type, name) , out type name : TEXCOORD@shCounter(2) + + #define shNormalInput(type) , in type normal : NORMAL + + #define shColourInput(type) , in type colour : COLOR + + #ifdef SH_VERTEX_SHADER + + #define shOutputPosition oPosition + #define shInputPosition iPosition + + + #define SH_BEGIN_PROGRAM \ + void main( \ + float4 iPosition : POSITION \ + , out float4 oPosition : POSITION + + #define SH_START_PROGRAM \ + ) \ + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shOutputColour(num) oColor##num + + #define shDeclareMrtOutput(num) , out float4 oColor##num : COLOR##num + + #define SH_BEGIN_PROGRAM \ + void main( \ + out float4 oColor0 : COLOR + + #define SH_START_PROGRAM \ + ) \ + + #endif + +#endif + +#if SH_GLSL == 1 + + @version 120 + + #define float2 vec2 + #define float3 vec3 + #define float4 vec4 + #define int2 ivec2 + #define int3 ivec3 + #define int4 ivec4 + #define shTexture2D sampler2D + #define shSample(tex, coord) texture2D(tex, coord) + #define shCubicSample(tex, coord) textureCube(tex, coord) + #define shLerp(a, b, t) mix(a, b, t) + #define shSaturate(a) clamp(a, 0.0, 1.0) + + #define shUniform(type, name) uniform type name; + + #define shSampler2D(name) uniform sampler2D name; @shUseSampler(name) + + #define shSamplerCube(name) uniform samplerCube name; @shUseSampler(name) + + #define shMatrixMult(m, v) (m * v) + + #define shOutputPosition gl_Position + + #define float4x4 mat4 + #define float3x3 mat3 + + // GLSL 1.3 + #if 0 + + // automatically recognized by ogre when the input name equals this + #define shInputPosition vertex + + #define shOutputColour(num) oColor##num + + #define shTangentInput(type) in type tangent; + #define shVertexInput(type, name) in type name; + #define shInput(type, name) in type name; + #define shOutput(type, name) out type name; + + // automatically recognized by ogre when the input name equals this + #define shNormalInput(type) in type normal; + #define shColourInput(type) in type colour; + + #ifdef SH_VERTEX_SHADER + + #define SH_BEGIN_PROGRAM \ + in float4 vertex; + #define SH_START_PROGRAM \ + void main(void) + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shDeclareMrtOutput(num) out vec4 oColor##num; + + #define SH_BEGIN_PROGRAM \ + out float4 oColor0; + #define SH_START_PROGRAM \ + void main(void) + + + #endif + + #endif + + // GLSL 1.2 + + #if 1 + + // automatically recognized by ogre when the input name equals this + #define shInputPosition vertex + + #define shOutputColour(num) gl_FragData[num] + + #define shTangentInput(type) attribute type tangent; + #define shVertexInput(type, name) attribute type name; + #define shInput(type, name) varying type name; + #define shOutput(type, name) varying type name; + + // automatically recognized by ogre when the input name equals this + #define shNormalInput(type) attribute type normal; + #define shColourInput(type) attribute type colour; + + #ifdef SH_VERTEX_SHADER + + #define SH_BEGIN_PROGRAM \ + attribute vec4 vertex; + #define SH_START_PROGRAM \ + void main(void) + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shDeclareMrtOutput(num) + + #define SH_BEGIN_PROGRAM + + #define SH_START_PROGRAM \ + void main(void) + + + #endif + + #endif +#endif diff --git a/extern/shiny/License.txt b/extern/shiny/License.txt new file mode 100644 index 0000000000..d89bcf3ad2 --- /dev/null +++ b/extern/shiny/License.txt @@ -0,0 +1,9 @@ +Copyright (c) 2012 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp new file mode 100644 index 0000000000..678ee25c96 --- /dev/null +++ b/extern/shiny/Main/Factory.cpp @@ -0,0 +1,583 @@ +#include "Factory.hpp" + +#include +#include + +#include +#include +#include + +#include "Platform.hpp" +#include "ScriptLoader.hpp" +#include "ShaderSet.hpp" +#include "MaterialInstanceTextureUnit.hpp" + +namespace sh +{ + Factory* Factory::sThis = 0; + + Factory& Factory::getInstance() + { + assert (sThis); + return *sThis; + } + + Factory* Factory::getInstancePtr() + { + return sThis; + } + + Factory::Factory (Platform* platform) + : mPlatform(platform) + , mShadersEnabled(true) + , mShaderDebugOutputEnabled(false) + , mCurrentLanguage(Language_None) + , mListener(NULL) + , mCurrentConfiguration(NULL) + , mCurrentLodConfiguration(NULL) + , mReadMicrocodeCache(false) + , mWriteMicrocodeCache(false) + , mReadSourceCache(false) + , mWriteSourceCache(false) + { + assert (!sThis); + sThis = this; + + mPlatform->setFactory(this); + } + + void Factory::loadAllFiles() + { + assert(mCurrentLanguage != Language_None); + + bool anyShaderDirty = false; + + if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt")) + { + std::ifstream file; + file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); + + std::string line; + while (getline(file, line)) + { + std::string sourceFile = line; + + if (!getline(file, line)) + assert(0); + + int modified = boost::lexical_cast(line); + + mShadersLastModified[sourceFile] = modified; + } + } + + // load configurations + { + ScriptLoader shaderSetLoader(".configuration"); + ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); + std::map nodes = shaderSetLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "configuration")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .configuration" << std::endl; + break; + } + + PropertySetGet newConfiguration; + newConfiguration.setParent(&mGlobalSettings); + + std::vector props = it->second->getChildren(); + for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) + { + std::string name = (*propIt)->getName(); + std::string val = (*propIt)->getValue(); + + newConfiguration.setProperty (name, makeProperty(val)); + } + + mConfigurations[it->first] = newConfiguration; + } + } + + // load lod configurations + { + ScriptLoader lodLoader(".lod"); + ScriptLoader::loadAllFiles (&lodLoader, mPlatform->getBasePath()); + std::map nodes = lodLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "lod_configuration")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .lod" << std::endl; + break; + } + + if (it->first == "0") + { + throw std::runtime_error("lod level 0 (max lod) can't have a configuration"); + } + + PropertySetGet newLod; + + std::vector props = it->second->getChildren(); + for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) + { + std::string name = (*propIt)->getName(); + std::string val = (*propIt)->getValue(); + + newLod.setProperty (name, makeProperty(val)); + } + + mLodConfigurations[boost::lexical_cast(it->first)] = newLod; + } + } + + // load shader sets + { + ScriptLoader shaderSetLoader(".shaderset"); + ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); + std::map nodes = shaderSetLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "shader_set")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl; + break; + } + + if (!it->second->findChild("profiles_cg")) + throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\""); + if (!it->second->findChild("profiles_hlsl")) + throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\""); + if (!it->second->findChild("source")) + throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\""); + if (!it->second->findChild("type")) + throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\""); + + std::vector profiles_cg; + boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" ")); + std::string cg_profile; + for (std::vector::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2) + { + if (mPlatform->isProfileSupported(*it2)) + { + cg_profile = *it2; + break; + } + } + + std::vector profiles_hlsl; + boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" ")); + std::string hlsl_profile; + for (std::vector::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2) + { + if (mPlatform->isProfileSupported(*it2)) + { + hlsl_profile = *it2; + break; + } + } + + std::string sourceFile = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); + + ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile, + sourceFile, + mPlatform->getBasePath(), + it->first, + &mGlobalSettings); + + int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceFile)); + if (mShadersLastModified.find(sourceFile) != mShadersLastModified.end() + && mShadersLastModified[sourceFile] != lastModified) + { + newSet.markDirty (); + anyShaderDirty = true; + } + + mShadersLastModified[sourceFile] = lastModified; + + mShaderSets.insert(std::make_pair(it->first, newSet)); + } + } + + // load materials + { + ScriptLoader materialLoader(".mat"); + ScriptLoader::loadAllFiles (&materialLoader, mPlatform->getBasePath()); + + std::map nodes = materialLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "material")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .mat" << std::endl; + break; + } + + MaterialInstance newInstance(it->first, this); + newInstance.create(mPlatform); + if (!mShadersEnabled) + newInstance.setShadersEnabled (false); + + newInstance.setSourceFile (it->second->m_fileName); + + std::vector props = it->second->getChildren(); + for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) + { + std::string name = (*propIt)->getName(); + + std::string val = (*propIt)->getValue(); + + if (name == "pass") + { + MaterialInstancePass* newPass = newInstance.createPass(); + std::vector props2 = (*propIt)->getChildren(); + for (std::vector::const_iterator propIt2 = props2.begin(); propIt2 != props2.end(); ++propIt2) + { + std::string name2 = (*propIt2)->getName(); + std::string val2 = (*propIt2)->getValue(); + + if (name2 == "shader_properties") + { + std::vector shaderProps = (*propIt2)->getChildren(); + for (std::vector::const_iterator shaderPropIt = shaderProps.begin(); shaderPropIt != shaderProps.end(); ++shaderPropIt) + { + std::string val = (*shaderPropIt)->getValue(); + newPass->mShaderProperties.setProperty((*shaderPropIt)->getName(), makeProperty(val)); + } + } + else if (name2 == "texture_unit") + { + MaterialInstanceTextureUnit* newTex = newPass->createTextureUnit(val2); + std::vector texProps = (*propIt2)->getChildren(); + for (std::vector::const_iterator texPropIt = texProps.begin(); texPropIt != texProps.end(); ++texPropIt) + { + std::string val = (*texPropIt)->getValue(); + newTex->setProperty((*texPropIt)->getName(), makeProperty(val)); + } + } + else + newPass->setProperty((*propIt2)->getName(), makeProperty(val2)); + } + } + else if (name == "parent") + newInstance.setParentInstance(val); + else + newInstance.setProperty((*propIt)->getName(), makeProperty(val)); + } + + if (newInstance.hasProperty("create_configuration")) + { + std::string config = retrieveValue(newInstance.getProperty("create_configuration"), NULL).get(); + newInstance.createForConfiguration (config, 0); + } + + mMaterials.insert (std::make_pair(it->first, newInstance)); + } + + // now that all materials are loaded, replace the parent names with the actual pointers to parent + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + std::string parent = it->second.getParentInstance(); + if (parent != "") + { + if (mMaterials.find (it->second.getParentInstance()) == mMaterials.end()) + throw std::runtime_error ("Unable to find parent for material instance \"" + it->first + "\""); + it->second.setParent(&mMaterials.find(parent)->second); + } + } + } + + if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !anyShaderDirty) + { + std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; + if (boost::filesystem::exists(file)) + { + mPlatform->deserializeShaders (file); + } + } + } + + Factory::~Factory () + { + if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache) + { + std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; + mPlatform->serializeShaders (file); + } + + if (mReadSourceCache) + { + // save the last modified time of shader sources + std::ofstream file; + file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); + + for (LastModifiedMap::const_iterator it = mShadersLastModified.begin(); it != mShadersLastModified.end(); ++it) + { + file << it->first << "\n" << it->second << std::endl; + } + + file.close(); + } + + delete mPlatform; + sThis = 0; + } + + MaterialInstance* Factory::searchInstance (const std::string& name) + { + if (mMaterials.find(name) != mMaterials.end()) + return &mMaterials.find(name)->second; + + return NULL; + } + + MaterialInstance* Factory::findInstance (const std::string& name) + { + assert (mMaterials.find(name) != mMaterials.end()); + return &mMaterials.find(name)->second; + } + + MaterialInstance* Factory::requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex) + { + MaterialInstance* m = searchInstance (name); + + if (configuration != "Default" && mConfigurations.find(configuration) == mConfigurations.end()) + return NULL; + + if (m) + { + // make sure all lod techniques below (higher lod) exist + int i = lodIndex; + while (i>0) + { + --i; + m->createForConfiguration (configuration, i); + + if (mListener) + mListener->materialCreated (m, configuration, i); + } + + m->createForConfiguration (configuration, lodIndex); + if (mListener) + mListener->materialCreated (m, configuration, lodIndex); + } + return m; + } + + MaterialInstance* Factory::createMaterialInstance (const std::string& name, const std::string& parentInstance) + { + if (parentInstance != "" && mMaterials.find(parentInstance) == mMaterials.end()) + throw std::runtime_error ("trying to clone material that does not exist"); + + MaterialInstance newInstance(name, this); + + if (!mShadersEnabled) + newInstance.setShadersEnabled(false); + + if (parentInstance != "") + newInstance.setParent (&mMaterials.find(parentInstance)->second); + + newInstance.create(mPlatform); + + mMaterials.insert (std::make_pair(name, newInstance)); + + return &mMaterials.find(name)->second; + } + + void Factory::destroyMaterialInstance (const std::string& name) + { + if (mMaterials.find(name) != mMaterials.end()) + mMaterials.erase(name); + } + + void Factory::setShadersEnabled (bool enabled) + { + mShadersEnabled = enabled; + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.setShadersEnabled(enabled); + } + } + + void Factory::setGlobalSetting (const std::string& name, const std::string& value) + { + bool changed = true; + if (mGlobalSettings.hasProperty(name)) + changed = (retrieveValue(mGlobalSettings.getProperty(name), NULL).get() != value); + + mGlobalSettings.setProperty (name, makeProperty(new StringValue(value))); + + if (changed) + { + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.destroyAll(); + } + } + } + + void Factory::setSharedParameter (const std::string& name, PropertyValuePtr value) + { + mPlatform->setSharedParameter(name, value); + } + + ShaderSet* Factory::getShaderSet (const std::string& name) + { + return &mShaderSets.find(name)->second; + } + + Platform* Factory::getPlatform () + { + return mPlatform; + } + + Language Factory::getCurrentLanguage () + { + return mCurrentLanguage; + } + + void Factory::setCurrentLanguage (Language lang) + { + bool changed = (mCurrentLanguage != lang); + mCurrentLanguage = lang; + + if (changed) + { + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.destroyAll(); + } + } + } + + MaterialInstance* Factory::getMaterialInstance (const std::string& name) + { + return findInstance(name); + } + + void Factory::setTextureAlias (const std::string& alias, const std::string& realName) + { + mTextureAliases[alias] = realName; + + // update the already existing texture units + for (std::map::iterator it = mTextureAliasInstances.begin(); it != mTextureAliasInstances.end(); ++it) + { + if (it->second == alias) + { + it->first->setTextureName(realName); + } + } + } + + std::string Factory::retrieveTextureAlias (const std::string& name) + { + if (mTextureAliases.find(name) != mTextureAliases.end()) + return mTextureAliases[name]; + else + return ""; + } + + PropertySetGet* Factory::getConfiguration (const std::string& name) + { + return &mConfigurations[name]; + } + + void Factory::registerConfiguration (const std::string& name, PropertySetGet configuration) + { + mConfigurations[name] = configuration; + mConfigurations[name].setParent (&mGlobalSettings); + } + + void Factory::registerLodConfiguration (int index, PropertySetGet configuration) + { + mLodConfigurations[index] = configuration; + } + + void Factory::setMaterialListener (MaterialListener* listener) + { + mListener = listener; + } + + void Factory::addTextureAliasInstance (const std::string& name, TextureUnitState* t) + { + mTextureAliasInstances[t] = name; + } + + void Factory::removeTextureAliasInstances (TextureUnitState* t) + { + mTextureAliasInstances.erase(t); + } + + void Factory::setActiveConfiguration (const std::string& configuration) + { + if (configuration == "Default") + mCurrentConfiguration = 0; + else + { + assert (mConfigurations.find(configuration) != mConfigurations.end()); + mCurrentConfiguration = &mConfigurations[configuration]; + } + } + + void Factory::setActiveLodLevel (int level) + { + if (level == 0) + mCurrentLodConfiguration = 0; + else + { + assert (mLodConfigurations.find(level) != mLodConfigurations.end()); + mCurrentLodConfiguration = &mLodConfigurations[level]; + } + } + + void Factory::setShaderDebugOutputEnabled (bool enabled) + { + mShaderDebugOutputEnabled = enabled; + } + + PropertySetGet* Factory::getCurrentGlobalSettings() + { + PropertySetGet* p = &mGlobalSettings; + + // current global settings are affected by active configuration & active lod configuration + + if (mCurrentConfiguration) + { + p = mCurrentConfiguration; + } + + if (mCurrentLodConfiguration) + { + mCurrentLodConfiguration->setParent(p); + p = mCurrentLodConfiguration; + } + + return p; + } + + void Factory::saveMaterials (const std::string& filename) + { + std::ofstream file; + file.open (filename.c_str ()); + + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.save(file); + } + + file.close(); + } + + void Factory::_ensureMaterial(const std::string& name, const std::string& configuration) + { + MaterialInstance* m = searchInstance (name); + assert(m); + m->createForConfiguration (configuration, 0); + } +} diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp new file mode 100644 index 0000000000..799dd71eb0 --- /dev/null +++ b/extern/shiny/Main/Factory.hpp @@ -0,0 +1,207 @@ +#ifndef SH_FACTORY_H +#define SH_FACTORY_H + +#include +#include + +#include "MaterialInstance.hpp" +#include "ShaderSet.hpp" +#include "Language.hpp" + +namespace sh +{ + class Platform; + + typedef std::map MaterialMap; + typedef std::map ShaderSetMap; + typedef std::map ConfigurationMap; + typedef std::map LodConfigurationMap; + typedef std::map LastModifiedMap; + + typedef std::map TextureAliasMap; + + /** + * @brief + * Allows you to be notified when a certain material was just created. Useful for changing material properties that you can't + * do in a .mat script (for example a series of animated textures) \n + * When receiving the event, you can get the platform material by calling m->getMaterial() + * and casting that to the platform specific material (e.g. for Ogre, sh::OgreMaterial) + */ + class MaterialListener + { + public: + virtual void materialCreated (MaterialInstance* m, const std::string& configuration, unsigned short lodIndex) = 0; + }; + + /** + * @brief + * The main interface class + */ + class Factory + { + public: + Factory(Platform* platform); + ///< @note Ownership of \a platform is transferred to this class, so you don't have to delete it. + + ~Factory(); + + /** + * Create a MaterialInstance, optionally copying all properties from \a parentInstance + * @param name name of the new instance + * @param name of the parent (optional) + * @return newly created instance + */ + MaterialInstance* createMaterialInstance (const std::string& name, const std::string& parentInstance = ""); + + /// @note It is safe to call this if the instance does not exist + void destroyMaterialInstance (const std::string& name); + + /// Use this to enable or disable shaders on-the-fly + void setShadersEnabled (bool enabled); + + /// write generated shaders to current directory, useful for debugging + void setShaderDebugOutputEnabled (bool enabled); + + /// Use this to manage user settings. \n + /// Global settings can be retrieved in shaders through a macro. \n + /// When a global setting is changed, the shaders that depend on them are recompiled automatically. + void setGlobalSetting (const std::string& name, const std::string& value); + + /// Adjusts the given shared parameter. \n + /// Internally, this will change all uniform parameters of this name marked with the macro \@shSharedParameter \n + /// @param name of the shared parameter + /// @param value of the parameter, use sh::makeProperty to construct this value + void setSharedParameter (const std::string& name, PropertyValuePtr value); + + Language getCurrentLanguage (); + + /// Switch between different shader languages (cg, glsl, hlsl) + void setCurrentLanguage (Language lang); + + /// Get a MaterialInstance by name + MaterialInstance* getMaterialInstance (const std::string& name); + + /// Register a configuration, which can then be used by switching the active material scheme + void registerConfiguration (const std::string& name, PropertySetGet configuration); + + /// Register a lod configuration, which can then be used by setting up lod distance values for the material \n + /// 0 refers to highest lod, so use 1 or higher as index parameter + void registerLodConfiguration (int index, PropertySetGet configuration); + + /// Set an alias name for a texture, the real name can then be retrieved with the "texture_alias" + /// property in a texture unit - this is useful if you don't know the name of your texture beforehand. \n + /// Example: \n + /// - In the material definition: texture_alias ReflectionMap \n + /// - At runtime: factory->setTextureAlias("ReflectionMap", "rtt_654654"); \n + /// You can call factory->setTextureAlias as many times as you want, and if the material was already created, its texture will be updated! + void setTextureAlias (const std::string& alias, const std::string& realName); + + /// Retrieve the real texture name for a texture alias (the real name is set by the user) + std::string retrieveTextureAlias (const std::string& name); + + /// Attach a listener for material created events + void setMaterialListener (MaterialListener* listener); + + /// Call this after you have set up basic stuff, like the shader language. + void loadAllFiles (); + + /// Controls writing of generated shader source code to the cache folder, so that the + /// (rather expensive) preprocessing step can be skipped on the next run. See Factory::setReadSourceCache \n + /// \note The default is off (no cache writing) + void setWriteSourceCache(bool write) { mWriteSourceCache = write; } + + /// Controls reading of generated shader sources from the cache folder + /// \note The default is off (no cache reading) + /// \note Even if microcode caching is enabled, generating (or caching) the source is still required due to the macros. + void setReadSourceCache(bool read) { mReadSourceCache = read; } + + /// Controls writing the microcode of the generated shaders to the cache folder. Microcode is machine independent + /// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform. + /// \note The default is off (no cache writing) + void setWriteMicrocodeCache(bool write) { mWriteMicrocodeCache = write; } + + /// Controls reading of shader microcode from the cache folder. Microcode is machine independent + /// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform. + /// \note The default is off (no cache reading) + void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; } + + /// Saves all the materials that were initially loaded from the file with this name + void saveMaterials (const std::string& filename); + + static Factory& getInstance(); + ///< Return instance of this class. + + static Factory* getInstancePtr(); + + /// Make sure a material technique is loaded.\n + /// You will probably never have to use this. + void _ensureMaterial(const std::string& name, const std::string& configuration); + + private: + + MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex); + ShaderSet* getShaderSet (const std::string& name); + PropertySetGet* getConfiguration (const std::string& name); + Platform* getPlatform (); + + PropertySetGet* getCurrentGlobalSettings(); + + void addTextureAliasInstance (const std::string& name, TextureUnitState* t); + void removeTextureAliasInstances (TextureUnitState* t); + + std::string getCacheFolder () { return mPlatform->getCacheFolder (); } + bool getReadSourceCache() { return mReadSourceCache; } + bool getWriteSourceCache() { return mReadSourceCache; } + public: + bool getWriteMicrocodeCache() { return mWriteMicrocodeCache; } // Fixme + + private: + void setActiveConfiguration (const std::string& configuration); + void setActiveLodLevel (int level); + + bool getShaderDebugOutputEnabled() { return mShaderDebugOutputEnabled; } + + std::map mTextureAliasInstances; + + friend class Platform; + friend class MaterialInstance; + friend class ShaderInstance; + friend class ShaderSet; + friend class TextureUnitState; + + private: + static Factory* sThis; + + bool mShadersEnabled; + bool mShaderDebugOutputEnabled; + + bool mReadMicrocodeCache; + bool mWriteMicrocodeCache; + bool mReadSourceCache; + bool mWriteSourceCache; + + MaterialMap mMaterials; + ShaderSetMap mShaderSets; + ConfigurationMap mConfigurations; + LodConfigurationMap mLodConfigurations; + LastModifiedMap mShadersLastModified; + + PropertySetGet mGlobalSettings; + + PropertySetGet* mCurrentConfiguration; + PropertySetGet* mCurrentLodConfiguration; + + TextureAliasMap mTextureAliases; + + Language mCurrentLanguage; + + MaterialListener* mListener; + + Platform* mPlatform; + + MaterialInstance* findInstance (const std::string& name); + MaterialInstance* searchInstance (const std::string& name); + }; +} + +#endif diff --git a/extern/shiny/Main/Language.hpp b/extern/shiny/Main/Language.hpp new file mode 100644 index 0000000000..20bf8ed61c --- /dev/null +++ b/extern/shiny/Main/Language.hpp @@ -0,0 +1,16 @@ +#ifndef SH_LANGUAGE_H +#define SH_LANGUAGE_H + +namespace sh +{ + enum Language + { + Language_CG, + Language_HLSL, + Language_GLSL, + Language_Count, + Language_None + }; +} + +#endif diff --git a/extern/shiny/Main/MaterialInstance.cpp b/extern/shiny/Main/MaterialInstance.cpp new file mode 100644 index 0000000000..0f8bcdda78 --- /dev/null +++ b/extern/shiny/Main/MaterialInstance.cpp @@ -0,0 +1,220 @@ +#include "MaterialInstance.hpp" + +#include + +#include "Factory.hpp" +#include "ShaderSet.hpp" + +namespace sh +{ + MaterialInstance::MaterialInstance (const std::string& name, Factory* f) + : mName(name) + , mShadersEnabled(true) + , mFactory(f) + , mListener(NULL) + { + } + + MaterialInstance::~MaterialInstance () + { + } + + void MaterialInstance::setParentInstance (const std::string& name) + { + mParentInstance = name; + } + + std::string MaterialInstance::getParentInstance () + { + return mParentInstance; + } + + void MaterialInstance::create (Platform* platform) + { + mMaterial = platform->createMaterial(mName); + + if (hasProperty ("shadow_caster_material")) + mMaterial->setShadowCasterMaterial (retrieveValue(getProperty("shadow_caster_material"), NULL).get()); + + if (hasProperty ("lod_values")) + mMaterial->setLodLevels (retrieveValue(getProperty("lod_values"), NULL).get()); + } + + void MaterialInstance::destroyAll () + { + if (hasProperty("create_configuration")) + return; + mMaterial->removeAll(); + mTexUnits.clear(); + } + + void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value) + { + PropertySetGet::setProperty (name, value); + destroyAll(); // trigger updates + } + + void MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex) + { + bool res = mMaterial->createConfiguration(configuration, lodIndex); + if (!res) + return; // listener was false positive + + if (mListener) + mListener->requestedConfiguration (this, configuration); + + mFactory->setActiveConfiguration (configuration); + mFactory->setActiveLodLevel (lodIndex); + + bool allowFixedFunction = true; + if (!mShadersEnabled && hasProperty("allow_fixed_function")) + { + allowFixedFunction = retrieveValue(getProperty("allow_fixed_function"), NULL).get(); + } + + bool useShaders = mShadersEnabled || !allowFixedFunction; + + // get passes of the top-most parent + PassVector passes = getPasses(); + if (passes.size() == 0) + throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); + + for (PassVector::iterator it = passes.begin(); it != passes.end(); ++it) + { + boost::shared_ptr pass = mMaterial->createPass (configuration, lodIndex); + it->copyAll (pass.get(), this); + + // texture samplers used in the shaders + std::vector usedTextureSamplersVertex; + std::vector usedTextureSamplersFragment; + + PropertySetGet* context = this; + + // create or retrieve shaders + bool hasVertex = it->hasProperty("vertex_program"); + bool hasFragment = it->hasProperty("fragment_program"); + if (useShaders) + { + it->setContext(context); + it->mShaderProperties.setContext(context); + if (hasVertex) + { + ShaderSet* vertex = mFactory->getShaderSet(retrieveValue(it->getProperty("vertex_program"), context).get()); + ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); + if (v) + { + pass->assignProgram (GPT_Vertex, v->getName()); + v->setUniformParameters (pass, &it->mShaderProperties); + + std::vector sharedParams = v->getSharedParameters (); + for (std::vector::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it) + { + pass->addSharedParameter (GPT_Vertex, *it); + } + + std::vector vector = v->getUsedSamplers (); + usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); + } + } + if (hasFragment) + { + ShaderSet* fragment = mFactory->getShaderSet(retrieveValue(it->getProperty("fragment_program"), context).get()); + ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); + if (f) + { + pass->assignProgram (GPT_Fragment, f->getName()); + f->setUniformParameters (pass, &it->mShaderProperties); + + std::vector sharedParams = f->getSharedParameters (); + for (std::vector::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it) + { + pass->addSharedParameter (GPT_Fragment, *it); + } + + std::vector vector = f->getUsedSamplers (); + usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); + } + } + } + + // create texture units + std::vector texUnits = it->getTexUnits(); + int i=0; + for (std::vector::iterator texIt = texUnits.begin(); texIt != texUnits.end(); ++texIt ) + { + // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled + bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); + bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); + if ( (foundVertex || foundFragment) + || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue(texIt->getProperty("create_in_ffp"), this).get())) + { + boost::shared_ptr texUnit = pass->createTextureUnitState (); + texIt->copyAll (texUnit.get(), context); + + mTexUnits.push_back(texUnit); + + // set texture unit indices (required by GLSL) + if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL) + { + pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); + + ++i; + } + } + } + } + + if (mListener) + mListener->createdConfiguration (this, configuration); + } + + Material* MaterialInstance::getMaterial () + { + return mMaterial.get(); + } + + MaterialInstancePass* MaterialInstance::createPass () + { + mPasses.push_back (MaterialInstancePass()); + mPasses.back().setContext(this); + return &mPasses.back(); + } + + PassVector MaterialInstance::getPasses() + { + if (mParent) + return static_cast(mParent)->getPasses(); + else + return mPasses; + } + + void MaterialInstance::setShadersEnabled (bool enabled) + { + if (enabled == mShadersEnabled) + return; + mShadersEnabled = enabled; + + // trigger updates + if (mMaterial.get()) + destroyAll(); + } + + void MaterialInstance::save (std::ofstream& stream) + { + stream << "material " << mName << "\n" + << "{\n"; + + if (mParent) + { + stream << "\t" << static_cast(mParent)->getName() << "\n"; + } + + const PropertyMap& properties = listProperties (); + for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) + { + stream << "\t" << it->first << " " << retrieveValue(getProperty(it->first), NULL).get() << "\n"; + } + + stream << "}\n"; + } +} diff --git a/extern/shiny/Main/MaterialInstance.hpp b/extern/shiny/Main/MaterialInstance.hpp new file mode 100644 index 0000000000..000f9d60c9 --- /dev/null +++ b/extern/shiny/Main/MaterialInstance.hpp @@ -0,0 +1,104 @@ +#ifndef SH_MATERIALINSTANCE_H +#define SH_MATERIALINSTANCE_H + +#include +#include + +#include "PropertyBase.hpp" +#include "Platform.hpp" +#include "MaterialInstancePass.hpp" + +namespace sh +{ + class Factory; + + typedef std::vector PassVector; + + /** + * @brief + * Allows you to be notified when a certain configuration for a material was just about to be created. \n + * Useful for adjusting some properties prior to the material being created (Or you could also re-create + * the whole material from scratch, i.e. use this as a method to create this material entirely in code) + */ + class MaterialInstanceListener + { + public: + virtual void requestedConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called before creating + virtual void createdConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called after creating + }; + + /** + * @brief + * A specific material instance, which has all required properties set + * (for example the diffuse & normal map, ambient/diffuse/specular values). \n + * Depending on these properties, the system will automatically select a shader permutation + * that suits these and create the backend materials / passes (provided by the \a Platform class). + */ + class MaterialInstance : public PropertySetGet + { + public: + MaterialInstance (const std::string& name, Factory* f); + virtual ~MaterialInstance (); + + MaterialInstancePass* createPass (); + PassVector getPasses(); ///< gets the passes of the top-most parent + + /// @attention Because the backend material passes are created on demand, the returned material here might not contain anything yet! + /// The only place where you should use this method, is for the MaterialInstance given by the MaterialListener::materialCreated event! + Material* getMaterial(); + + /// attach a \a MaterialInstanceListener to this specific material (as opposed to \a MaterialListener, which listens to all materials) + void setListener (MaterialInstanceListener* l) { mListener = l; } + + std::string getName() { return mName; } + + virtual void setProperty (const std::string& name, PropertyValuePtr value); + + private: + void setParentInstance (const std::string& name); + std::string getParentInstance (); + + void create (Platform* platform); + void createForConfiguration (const std::string& configuration, unsigned short lodIndex); + + void destroyAll (); + + void setShadersEnabled (bool enabled); + + void setSourceFile(const std::string& sourceFile) { mSourceFile = sourceFile; } + + std::string getSourceFile() { return mSourceFile; } + ///< get the name of the file this material was read from, or empty if it was created dynamically by code + + void save (std::ofstream& stream); + ///< this will only save the properties, not the passes and texture units, and as such + /// is only intended to be used for derived materials + + friend class Factory; + + + private: + std::string mParentInstance; + ///< this is only used during the file-loading phase. an instance could be loaded before its parent is loaded, + /// so initially only the parent's name is written to this member. + /// once all instances are loaded, the actual mParent pointer (from PropertySetGet class) can be set + + std::vector< boost::shared_ptr > mTexUnits; + + MaterialInstanceListener* mListener; + + PassVector mPasses; + + std::string mName; + + std::string mSourceFile; + + boost::shared_ptr mMaterial; + + bool mShadersEnabled; + + Factory* mFactory; + }; +} + +#endif diff --git a/extern/shiny/Main/MaterialInstancePass.cpp b/extern/shiny/Main/MaterialInstancePass.cpp new file mode 100644 index 0000000000..b14476f4e7 --- /dev/null +++ b/extern/shiny/Main/MaterialInstancePass.cpp @@ -0,0 +1,16 @@ +#include "MaterialInstancePass.hpp" + +namespace sh +{ + + MaterialInstanceTextureUnit* MaterialInstancePass::createTextureUnit (const std::string& name) + { + mTexUnits.push_back(MaterialInstanceTextureUnit(name)); + return &mTexUnits.back(); + } + + std::vector MaterialInstancePass::getTexUnits () + { + return mTexUnits; + } +} diff --git a/extern/shiny/Main/MaterialInstancePass.hpp b/extern/shiny/Main/MaterialInstancePass.hpp new file mode 100644 index 0000000000..7d7330f705 --- /dev/null +++ b/extern/shiny/Main/MaterialInstancePass.hpp @@ -0,0 +1,29 @@ +#ifndef SH_MATERIALINSTANCEPASS_H +#define SH_MATERIALINSTANCEPASS_H + +#include + +#include "PropertyBase.hpp" +#include "MaterialInstanceTextureUnit.hpp" + +namespace sh +{ + /** + * @brief + * Holds properties of a single texture unit in a \a MaterialInstancePass. \n + * No inheritance here for now. + */ + class MaterialInstancePass : public PropertySetGet + { + public: + MaterialInstanceTextureUnit* createTextureUnit (const std::string& name); + + PropertySetGet mShaderProperties; + + std::vector getTexUnits (); + private: + std::vector mTexUnits; + }; +} + +#endif diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.cpp b/extern/shiny/Main/MaterialInstanceTextureUnit.cpp new file mode 100644 index 0000000000..0e3078af34 --- /dev/null +++ b/extern/shiny/Main/MaterialInstanceTextureUnit.cpp @@ -0,0 +1,14 @@ +#include "MaterialInstanceTextureUnit.hpp" + +namespace sh +{ + MaterialInstanceTextureUnit::MaterialInstanceTextureUnit (const std::string& name) + : mName(name) + { + } + + std::string MaterialInstanceTextureUnit::getName() const + { + return mName; + } +} diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.hpp b/extern/shiny/Main/MaterialInstanceTextureUnit.hpp new file mode 100644 index 0000000000..ae9f54fd2d --- /dev/null +++ b/extern/shiny/Main/MaterialInstanceTextureUnit.hpp @@ -0,0 +1,26 @@ +#ifndef SH_MATERIALINSTANCETEXTUREUNIT_H +#define SH_MATERIALINSTANCETEXTUREUNIT_H + +#include "PropertyBase.hpp" + +namespace sh +{ + /** + * @brief + * A single texture unit state that belongs to a \a MaterialInstancePass \n + * this is not the real "backend" \a TextureUnitState (provided by \a Platform), + * it is merely a placeholder for properties. \n + * @note The backend \a TextureUnitState will only be created if this texture unit is + * actually used (i.e. referenced in the shader, or marked with property create_in_ffp = true). + */ + class MaterialInstanceTextureUnit : public PropertySetGet + { + public: + MaterialInstanceTextureUnit (const std::string& name); + std::string getName() const; + private: + std::string mName; + }; +} + +#endif diff --git a/extern/shiny/Main/Platform.cpp b/extern/shiny/Main/Platform.cpp new file mode 100644 index 0000000000..94b4f872ae --- /dev/null +++ b/extern/shiny/Main/Platform.cpp @@ -0,0 +1,94 @@ +#include "Platform.hpp" + +#include + +#include "Factory.hpp" + +namespace sh +{ + Platform::Platform (const std::string& basePath) + : mBasePath(basePath) + , mCacheFolder("./") + , mShaderCachingEnabled(false) + { + } + + Platform::~Platform () + { + } + + void Platform::setFactory (Factory* factory) + { + mFactory = factory; + } + + std::string Platform::getBasePath () + { + return mBasePath; + } + + bool Platform::supportsMaterialQueuedListener () + { + return false; + } + + bool Platform::supportsShaderSerialization () + { + return false; + } + + MaterialInstance* Platform::fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex) + { + return mFactory->requestMaterial (name, configuration, lodIndex); + } + + void Platform::serializeShaders (const std::string& file) + { + throw std::runtime_error ("Shader serialization not supported by this platform"); + } + + void Platform::deserializeShaders (const std::string& file) + { + throw std::runtime_error ("Shader serialization not supported by this platform"); + } + + void Platform::setCacheFolder (const std::string& folder) + { + mCacheFolder = folder; + } + + void Platform::setShaderCachingEnabled (bool enabled) + { + mShaderCachingEnabled = enabled; + } + + std::string Platform::getCacheFolder() const + { + return mCacheFolder; + } + + // ------------------------------------------------------------------------------ + + bool TextureUnitState::setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context) + { + if (name == "texture_alias") + { + std::string aliasName = retrieveValue(value, context).get(); + + Factory::getInstance().addTextureAliasInstance (aliasName, this); + + setTextureName (Factory::getInstance().retrieveTextureAlias (aliasName)); + + return true; + } + else + return false; + } + + TextureUnitState::~TextureUnitState() + { + Factory* f = Factory::getInstancePtr (); + if (f) + f->removeTextureAliasInstances (this); + } +} diff --git a/extern/shiny/Main/Platform.hpp b/extern/shiny/Main/Platform.hpp new file mode 100644 index 0000000000..1b095e9576 --- /dev/null +++ b/extern/shiny/Main/Platform.hpp @@ -0,0 +1,145 @@ +#ifndef SH_PLATFORM_H +#define SH_PLATFORM_H + +#include + +#include + +#include "Language.hpp" +#include "PropertyBase.hpp" + +namespace sh +{ + class Factory; + class MaterialInstance; + + enum GpuProgramType + { + GPT_Vertex, + GPT_Fragment + // GPT_Geometry + }; + + // These classes are supposed to be filled by the platform implementation + class GpuProgram + { + public: + virtual bool getSupported () = 0; ///< @return true if the compilation was successful + + /// @param name name of the uniform in the shader + /// @param autoConstantName name of the auto constant (for example world_viewproj_matrix) + /// @param extraInfo if any extra info is needed (e.g. light index), put it here + virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = "") = 0; + }; + + class TextureUnitState : public PropertySet + { + public: + virtual ~TextureUnitState(); + + virtual void setTextureName (const std::string& textureName) = 0; + + protected: + virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context); + }; + + class Pass : public PropertySet + { + public: + virtual boost::shared_ptr createTextureUnitState () = 0; + virtual void assignProgram (GpuProgramType type, const std::string& name) = 0; + + /// @param type gpu program type + /// @param name name of the uniform in the shader + /// @param vt type of value, e.g. vector4 + /// @param value value to set + /// @param context used for retrieving linked values + virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) = 0; + + virtual void setTextureUnitIndex (int programType, const std::string& name, int index) = 0; + + virtual void addSharedParameter (int type, const std::string& name) = 0; + }; + + class Material : public PropertySet + { + public: + virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex) = 0; + virtual bool createConfiguration (const std::string& name, unsigned short lodIndex) = 0; ///< @return false if already exists + virtual void removeAll () = 0; ///< remove all configurations + + virtual void setLodLevels (const std::string& lodLevels) = 0; + + virtual void setShadowCasterMaterial (const std::string& name) = 0; + }; + + class Platform + { + public: + Platform (const std::string& basePath); + virtual ~Platform (); + + void setShaderCachingEnabled (bool enabled); + + /// set the folder to use for shader caching + void setCacheFolder (const std::string& folder); + + private: + virtual boost::shared_ptr createMaterial (const std::string& name) = 0; + + virtual boost::shared_ptr createGpuProgram ( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, Language lang) = 0; + + virtual void setSharedParameter (const std::string& name, PropertyValuePtr value) = 0; + + virtual bool isProfileSupported (const std::string& profile) = 0; + + virtual void serializeShaders (const std::string& file); + virtual void deserializeShaders (const std::string& file); + + std::string getCacheFolder () const; + + friend class Factory; + friend class MaterialInstance; + friend class ShaderInstance; + + protected: + /** + * this will be \a true if the platform supports serialization (writing shader microcode + * to disk) and deserialization (create gpu program from saved microcode) + */ + virtual bool supportsShaderSerialization (); + + /** + * this will be \a true if the platform supports a listener that notifies the system + * whenever a material is requested for rendering. if this is supported, shaders can be + * compiled on-demand when needed (and not earlier) + * @todo the Factory is not designed yet to handle the case where this method returns false + */ + virtual bool supportsMaterialQueuedListener (); + + /** + * fire event: material requested for rendering + * @param name material name + * @param configuration requested configuration + */ + MaterialInstance* fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex); + + std::string mCacheFolder; + Factory* mFactory; + + protected: + bool mShaderCachingEnabled; + + private: + void setFactory (Factory* factory); + + std::string mBasePath; + std::string getBasePath(); + }; +} + +#endif diff --git a/extern/shiny/Main/Preprocessor.cpp b/extern/shiny/Main/Preprocessor.cpp new file mode 100644 index 0000000000..1a97668bcc --- /dev/null +++ b/extern/shiny/Main/Preprocessor.cpp @@ -0,0 +1,99 @@ +#include "Preprocessor.hpp" + +#include +#include +#include + +namespace sh +{ + std::string Preprocessor::preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name) + { + std::stringstream returnString; + + // current file position is saved for exception handling + boost::wave::util::file_position_type current_position; + + try + { + // This token type is one of the central types used throughout the library. + // It is a template parameter to some of the public classes and instances + // of this type are returned from the iterators. + typedef boost::wave::cpplexer::lex_token<> token_type; + + // The template boost::wave::cpplexer::lex_iterator<> is the lexer type to + // to use as the token source for the preprocessing engine. It is + // parametrized with the token type. + typedef boost::wave::cpplexer::lex_iterator lex_iterator_type; + + // This is the resulting context type. The first template parameter should + // match the iterator type used during construction of the context + // instance (see below). It is the type of the underlying input stream. + typedef boost::wave::context + context_type; + + // The preprocessor iterator shouldn't be constructed directly. It is + // generated through a wave::context<> object. This wave:context<> object + // is additionally used to initialize and define different parameters of + // the actual preprocessing. + // + // The preprocessing of the input stream is done on the fly behind the + // scenes during iteration over the range of context_type::iterator_type + // instances. + context_type ctx (source.begin(), source.end(), name.c_str()); + ctx.add_include_path(includePath.c_str()); + for (std::vector::iterator it = definitions.begin(); it != definitions.end(); ++it) + { + ctx.add_macro_definition(*it); + } + + // Get the preprocessor iterators and use them to generate the token + // sequence. + context_type::iterator_type first = ctx.begin(); + context_type::iterator_type last = ctx.end(); + + // The input stream is preprocessed for you while iterating over the range + // [first, last). The dereferenced iterator returns tokens holding + // information about the preprocessed input stream, such as token type, + // token value, and position. + while (first != last) + { + current_position = (*first).get_position(); + returnString << (*first).get_value(); + ++first; + } + } + catch (boost::wave::cpp_exception const& e) + { + // some preprocessing error + std::stringstream error; + error + << e.file_name() << "(" << e.line_no() << "): " + << e.description(); + throw std::runtime_error(error.str()); + } + catch (std::exception const& e) + { + // use last recognized token to retrieve the error position + std::stringstream error; + error + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "exception caught: " << e.what(); + throw std::runtime_error(error.str()); + } + catch (...) + { + // use last recognized token to retrieve the error position + std::stringstream error; + error + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "unexpected exception caught."; + throw std::runtime_error(error.str()); + } + + return returnString.str(); + } +} diff --git a/extern/shiny/Main/Preprocessor.hpp b/extern/shiny/Main/Preprocessor.hpp new file mode 100644 index 0000000000..7ee30ae7fc --- /dev/null +++ b/extern/shiny/Main/Preprocessor.hpp @@ -0,0 +1,69 @@ +#ifndef SH_PREPROCESSOR_H +#define SH_PREPROCESSOR_H + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace sh +{ + /** + * @brief A simple interface for the boost::wave preprocessor + */ + class Preprocessor + { + public: + /** + * @brief Run a shader source string through the preprocessor + * @param source source string + * @param includePath path to search for includes (that are included with #include) + * @param definitions macros to predefine (vector of strings of the format MACRO=value, or just MACRO to define it as 1) + * @param name name to use for error messages + * @return processed string + */ + static std::string preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name); + }; + + + + class emit_custom_line_directives_hooks + : public boost::wave::context_policies::default_preprocessing_hooks + { + public: + + template + bool + emit_line_directive(ContextT const& ctx, ContainerT &pending, + typename ContextT::token_type const& act_token) + { + // emit a #line directive showing the relative filename instead + typename ContextT::position_type pos = act_token.get_position(); + unsigned int column = 1; + + typedef typename ContextT::token_type result_type; + + // no line directives for now + pos.set_column(column); + pending.push_back(result_type(boost::wave::T_GENERATEDNEWLINE, "\n", pos)); + + return true; + } + }; + + +} + +#endif diff --git a/extern/shiny/Main/PropertyBase.cpp b/extern/shiny/Main/PropertyBase.cpp new file mode 100644 index 0000000000..0c39e5c1e7 --- /dev/null +++ b/extern/shiny/Main/PropertyBase.cpp @@ -0,0 +1,268 @@ +#include "PropertyBase.hpp" + +#include +#include + +#include +#include + +namespace sh +{ + + IntValue::IntValue(int in) + : mValue(in) + { + } + + IntValue::IntValue(const std::string& in) + { + mValue = boost::lexical_cast(in); + } + + std::string IntValue::serialize() + { + return boost::lexical_cast(mValue); + } + + // ------------------------------------------------------------------------------ + + BooleanValue::BooleanValue (bool in) + : mValue(in) + { + } + + BooleanValue::BooleanValue (const std::string& in) + { + if (in == "true") + mValue = true; + else if (in == "false") + mValue = false; + else + { + std::cerr << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue" << std::endl; + mValue = false; + } + } + + std::string BooleanValue::serialize () + { + if (mValue) + return "true"; + else + return "false"; + } + + // ------------------------------------------------------------------------------ + + StringValue::StringValue (const std::string& in) + { + mStringValue = in; + } + + std::string StringValue::serialize() + { + return mStringValue; + } + + // ------------------------------------------------------------------------------ + + LinkedValue::LinkedValue (const std::string& in) + { + mStringValue = in; + mStringValue.erase(0, 1); + } + + std::string LinkedValue::serialize() + { + throw std::runtime_error ("can't directly get a linked value"); + } + + std::string LinkedValue::get(PropertySetGet* context) const + { + PropertyValuePtr p = context->getProperty(mStringValue); + return retrieveValue(p, NULL).get(); + } + + // ------------------------------------------------------------------------------ + + FloatValue::FloatValue (float in) + { + mValue = in; + } + + FloatValue::FloatValue (const std::string& in) + { + mValue = boost::lexical_cast(in); + } + + std::string FloatValue::serialize () + { + return boost::lexical_cast(mValue); + } + + // ------------------------------------------------------------------------------ + + Vector2::Vector2 (float x, float y) + : mX(x) + , mY(y) + { + } + + Vector2::Vector2 (const std::string& in) + { + std::vector tokens; + boost::split(tokens, in, boost::is_any_of(" ")); + assert ((tokens.size() == 2) && "Invalid Vector2 conversion"); + mX = boost::lexical_cast (tokens[0]); + mY = boost::lexical_cast (tokens[1]); + } + + std::string Vector2::serialize () + { + return boost::lexical_cast(mX) + " " + + boost::lexical_cast(mY); + } + + // ------------------------------------------------------------------------------ + + Vector3::Vector3 (float x, float y, float z) + : mX(x) + , mY(y) + , mZ(z) + { + } + + Vector3::Vector3 (const std::string& in) + { + std::vector tokens; + boost::split(tokens, in, boost::is_any_of(" ")); + assert ((tokens.size() == 3) && "Invalid Vector3 conversion"); + mX = boost::lexical_cast (tokens[0]); + mY = boost::lexical_cast (tokens[1]); + mZ = boost::lexical_cast (tokens[2]); + } + + std::string Vector3::serialize () + { + return boost::lexical_cast(mX) + " " + + boost::lexical_cast(mY) + " " + + boost::lexical_cast(mZ); + } + + // ------------------------------------------------------------------------------ + + Vector4::Vector4 (float x, float y, float z, float w) + : mX(x) + , mY(y) + , mZ(z) + , mW(w) + { + } + + Vector4::Vector4 (const std::string& in) + { + std::vector tokens; + boost::split(tokens, in, boost::is_any_of(" ")); + assert ((tokens.size() == 4) && "Invalid Vector4 conversion"); + mX = boost::lexical_cast (tokens[0]); + mY = boost::lexical_cast (tokens[1]); + mZ = boost::lexical_cast (tokens[2]); + mW = boost::lexical_cast (tokens[3]); + } + + std::string Vector4::serialize () + { + return boost::lexical_cast(mX) + " " + + boost::lexical_cast(mY) + " " + + boost::lexical_cast(mZ) + " " + + boost::lexical_cast(mW); + } + + // ------------------------------------------------------------------------------ + + void PropertySet::setProperty (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) + { + if (!setPropertyOverride (name, value, context)) + std::cerr << "sh::PropertySet: Warning: No match for property with name '" << name << "'" << std::endl; + } + + bool PropertySet::setPropertyOverride (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) + { + // if we got here, none of the sub-classes was able to make use of the property + return false; + } + + // ------------------------------------------------------------------------------ + + PropertySetGet::PropertySetGet (PropertySetGet* parent) + : mParent(parent) + , mContext(NULL) + { + } + + PropertySetGet::PropertySetGet () + : mParent(NULL) + , mContext(NULL) + { + } + + void PropertySetGet::setParent (PropertySetGet* parent) + { + mParent = parent; + } + + void PropertySetGet::setContext (PropertySetGet* context) + { + mContext = context; + } + + PropertySetGet* PropertySetGet::getContext() + { + return mContext; + } + + void PropertySetGet::setProperty (const std::string& name, PropertyValuePtr value) + { + mProperties [name] = value; + } + + PropertyValuePtr& PropertySetGet::getProperty (const std::string& name) + { + bool found = (mProperties.find(name) != mProperties.end()); + + if (!found) + { + if (!mParent) + throw std::runtime_error ("Trying to retrieve property \"" + name + "\" that does not exist"); + else + return mParent->getProperty (name); + } + else + return mProperties[name]; + } + + bool PropertySetGet::hasProperty (const std::string& name) + { + bool found = (mProperties.find(name) != mProperties.end()); + + if (!found) + { + if (!mParent) + return false; + else + return mParent->hasProperty (name); + } + else + return true; + } + + void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context) + { + if (mParent) + mParent->copyAll (target, context); + for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) + { + target->setProperty(it->first, it->second, context); + } + } +} diff --git a/extern/shiny/Main/PropertyBase.hpp b/extern/shiny/Main/PropertyBase.hpp new file mode 100644 index 0000000000..240acce81b --- /dev/null +++ b/extern/shiny/Main/PropertyBase.hpp @@ -0,0 +1,235 @@ +#ifndef SH_PROPERTYBASE_H +#define SH_PROPERTYBASE_H + +#include +#include + +#include + +namespace sh +{ + class StringValue; + class PropertySetGet; + class LinkedValue; + + enum ValueType + { + VT_String, + VT_Int, + VT_Float, + VT_Vector2, + VT_Vector3, + VT_Vector4 + }; + + class PropertyValue + { + public: + PropertyValue() {} + + virtual ~PropertyValue() {} + + std::string _getStringValue() { return mStringValue; } + + virtual std::string serialize() = 0; + + protected: + std::string mStringValue; ///< this will possibly not contain anything in the specialised classes + }; + typedef boost::shared_ptr PropertyValuePtr; + + class StringValue : public PropertyValue + { + public: + StringValue (const std::string& in); + std::string get() const { return mStringValue; } + + virtual std::string serialize(); + }; + + /** + * @brief Used for retrieving a named property from a context + */ + class LinkedValue : public PropertyValue + { + public: + LinkedValue (const std::string& in); + + std::string get(PropertySetGet* context) const; + + virtual std::string serialize(); + }; + + class FloatValue : public PropertyValue + { + public: + FloatValue (float in); + FloatValue (const std::string& in); + float get() const { return mValue; } + + virtual std::string serialize(); + private: + float mValue; + }; + + class IntValue : public PropertyValue + { + public: + IntValue (int in); + IntValue (const std::string& in); + int get() const { return mValue; } + + virtual std::string serialize(); + private: + int mValue; + }; + + class BooleanValue : public PropertyValue + { + public: + BooleanValue (bool in); + BooleanValue (const std::string& in); + bool get() const { return mValue; } + + virtual std::string serialize(); + private: + bool mValue; + }; + + class Vector2 : public PropertyValue + { + public: + Vector2 (float x, float y); + Vector2 (const std::string& in); + + float mX, mY; + + virtual std::string serialize(); + }; + + class Vector3 : public PropertyValue + { + public: + Vector3 (float x, float y, float z); + Vector3 (const std::string& in); + + float mX, mY, mZ; + + virtual std::string serialize(); + }; + + class Vector4 : public PropertyValue + { + public: + Vector4 (float x, float y, float z, float w); + Vector4 (const std::string& in); + + float mX, mY, mZ, mW; + + virtual std::string serialize(); + }; + + /// \brief base class that allows setting properties with any kind of value-type + class PropertySet + { + public: + void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); + + protected: + virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); + ///< @return \a true if the specified property was found, or false otherwise + }; + + typedef std::map PropertyMap; + + /// \brief base class that allows setting properties with any kind of value-type and retrieving them + class PropertySetGet + { + public: + PropertySetGet (PropertySetGet* parent); + PropertySetGet (); + + virtual ~PropertySetGet() {} + + void copyAll (PropertySet* target, PropertySetGet* context); ///< call setProperty for each property/value pair stored in \a this + + void setParent (PropertySetGet* parent); + void setContext (PropertySetGet* context); + PropertySetGet* getContext(); + + virtual void setProperty (const std::string& name, PropertyValuePtr value); + PropertyValuePtr& getProperty (const std::string& name); + + const PropertyMap& listProperties() { return mProperties; } + + bool hasProperty (const std::string& name); + + private: + PropertyMap mProperties; + + protected: + PropertySetGet* mParent; + ///< the parent can provide properties as well (when they are retrieved via getProperty) \n + /// multiple levels of inheritance are also supported \n + /// children can override properties of their parents + + PropertySetGet* mContext; + ///< used to retrieve linked property values + }; + + template + static T retrieveValue (boost::shared_ptr& value, PropertySetGet* context) + { + if (typeid(*value).name() == typeid(LinkedValue).name()) + { + std::string v = static_cast(value.get())->get(context); + PropertyValuePtr newVal = PropertyValuePtr (new StringValue(v)); + return retrieveValue(newVal, NULL); + } + if (typeid(T).name() == typeid(*value).name()) + { + // requested type is the same as source type, only have to cast it + return *static_cast(value.get()); + } + + if ((typeid(T).name() == typeid(StringValue).name()) + && typeid(*value).name() != typeid(StringValue).name()) + { + // if string type is requested and value is not string, use serialize method to convert to string + T* ptr = new T (value->serialize()); // note that T is always StringValue here, but we can't use it here + value = boost::shared_ptr (static_cast(ptr)); + return *ptr; + } + + { + // remaining case: deserialization from string by passing the string to constructor of class T + T* ptr = new T(value->_getStringValue()); + PropertyValuePtr newVal (static_cast(ptr)); + value = newVal; + return *ptr; + } + } + ///< + /// @brief alternate version that supports linked values (use of $variables in parent material) + /// @note \a value is changed in-place to the converted object + /// @return converted object \n + + /// Create a property from a string + inline PropertyValuePtr makeProperty (const std::string& prop) + { + if (prop.size() > 1 && prop[0] == '$') + return PropertyValuePtr (static_cast(new LinkedValue(prop))); + else + return PropertyValuePtr (static_cast (new StringValue(prop))); + } + + template + /// Create a property of any type + /// Example: sh::makeProperty\ (new sh::Vector4(1, 1, 1, 1)) + inline PropertyValuePtr makeProperty (T* p) + { + return PropertyValuePtr ( static_cast(p) ); + } +} + +#endif diff --git a/extern/shiny/Main/ScriptLoader.cpp b/extern/shiny/Main/ScriptLoader.cpp new file mode 100644 index 0000000000..a8971dc87d --- /dev/null +++ b/extern/shiny/Main/ScriptLoader.cpp @@ -0,0 +1,401 @@ +#include "ScriptLoader.hpp" + +#include +#include +#include +#include + +#include + +namespace sh +{ + void ScriptLoader::loadAllFiles(ScriptLoader* c, const std::string& path) + { + for ( boost::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir ) + { + boost::filesystem::path p(*dir); + if(p.extension() == c->m_fileEnding) + { + c->m_currentFileName = (*dir).path().string(); + std::ifstream in((*dir).path().string().c_str(), std::ios::binary); + c->parseScript(in); + } + } + } + + ScriptLoader::ScriptLoader(const std::string& fileEnding) + { + m_fileEnding = fileEnding; + } + + ScriptLoader::~ScriptLoader() + { + clearScriptList(); + } + + void ScriptLoader::clearScriptList() + { + std::map ::iterator i; + for (i = m_scriptList.begin(); i != m_scriptList.end(); i++) + { + delete i->second; + } + m_scriptList.clear(); + } + + ScriptNode *ScriptLoader::getConfigScript(const std::string &name) + { + std::map ::iterator i; + + std::string key = name; + i = m_scriptList.find(key); + + //If found.. + if (i != m_scriptList.end()) + { + return i->second; + } + else + { + return NULL; + } + } + + std::map ScriptLoader::getAllConfigScripts () + { + return m_scriptList; + } + + void ScriptLoader::parseScript(std::ifstream &stream) + { + //Get first token + _nextToken(stream); + if (tok == TOKEN_EOF) + { + stream.close(); + return; + } + + //Parse the script + _parseNodes(stream, 0); + + stream.close(); + } + + void ScriptLoader::_nextToken(std::ifstream &stream) + { + //EOF token + if (!stream.good()) + { + tok = TOKEN_EOF; + return; + } + + //(Get next character) + int ch = stream.get(); + + while ((ch == ' ' || ch == 9) && !stream.eof()) + { //Skip leading spaces / tabs + ch = stream.get(); + } + + if (!stream.good()) + { + tok = TOKEN_EOF; + return; + } + + //Newline token + if (ch == '\r' || ch == '\n') + { + do + { + ch = stream.get(); + } while ((ch == '\r' || ch == '\n') && !stream.eof()); + + stream.unget(); + + tok = TOKEN_NewLine; + return; + } + + //Open brace token + else if (ch == '{') + { + tok = TOKEN_OpenBrace; + return; + } + + //Close brace token + else if (ch == '}') + { + tok = TOKEN_CloseBrace; + return; + } + + //Text token + if (ch < 32 || ch > 122) //Verify valid char + { + throw std::runtime_error("Parse Error: Invalid character, ConfigLoader::load()"); + } + + tokVal = ""; + tok = TOKEN_Text; + do + { + //Skip comments + if (ch == '/') + { + int ch2 = stream.peek(); + + //C++ style comment (//) + if (ch2 == '/') + { + stream.get(); + do + { + ch = stream.get(); + } while (ch != '\r' && ch != '\n' && !stream.eof()); + + tok = TOKEN_NewLine; + return; + } + } + + //Add valid char to tokVal + tokVal += (char)ch; + + //Next char + ch = stream.get(); + + } while (ch > 32 && ch <= 122 && !stream.eof()); + + stream.unget(); + + return; + } + + void ScriptLoader::_skipNewLines(std::ifstream &stream) + { + while (tok == TOKEN_NewLine) + { + _nextToken(stream); + } + } + + void ScriptLoader::_parseNodes(std::ifstream &stream, ScriptNode *parent) + { + typedef std::pair ScriptItem; + + while (true) + { + switch (tok) + { + //Node + case TOKEN_Text: + { + //Add the new node + ScriptNode *newNode; + if (parent) + { + newNode = parent->addChild(tokVal); + } + else + { + newNode = new ScriptNode(0, tokVal); + } + + //Get values + _nextToken(stream); + std::string valueStr; + int i=0; + while (tok == TOKEN_Text) + { + if (i == 0) + valueStr += tokVal; + else + valueStr += " " + tokVal; + _nextToken(stream); + ++i; + } + newNode->setValue(valueStr); + + //Add root nodes to scriptList + if (!parent) + { + std::string key; + + if (newNode->getValue() == "") + throw std::runtime_error("Root node must have a name (\"" + newNode->getName() + "\")"); + key = newNode->getValue(); + + m_scriptList.insert(ScriptItem(key, newNode)); + } + + _skipNewLines(stream); + + //Add any sub-nodes + if (tok == TOKEN_OpenBrace) + { + //Parse nodes + _nextToken(stream); + _parseNodes(stream, newNode); + //Check for matching closing brace + if (tok != TOKEN_CloseBrace) + { + throw std::runtime_error("Parse Error: Expecting closing brace"); + } + _nextToken(stream); + _skipNewLines(stream); + } + + newNode->m_fileName = m_currentFileName; + + break; + } + + //Out of place brace + case TOKEN_OpenBrace: + throw std::runtime_error("Parse Error: Opening brace out of plane"); + break; + + //Return if end of nodes have been reached + case TOKEN_CloseBrace: + return; + + //Return if reached end of file + case TOKEN_EOF: + return; + + case TOKEN_NewLine: + _nextToken(stream); + break; + } + }; + } + + ScriptNode::ScriptNode(ScriptNode *parent, const std::string &name) + { + m_name = name; + m_parent = parent; + _removeSelf = true; //For proper destruction + m_lastChildFound = -1; + + //Add self to parent's child list (unless this is the root node being created) + if (parent != NULL) + { + m_parent->m_children.push_back(this); + _iter = --(m_parent->m_children.end()); + } + } + + ScriptNode::~ScriptNode() + { + //Delete all children + std::vector::iterator i; + for (i = m_children.begin(); i != m_children.end(); i++) + { + ScriptNode *node = *i; + node->_removeSelf = false; + delete node; + } + m_children.clear(); + + //Remove self from parent's child list + if (_removeSelf && m_parent != NULL) + { + m_parent->m_children.erase(_iter); + } + } + + ScriptNode *ScriptNode::addChild(const std::string &name, bool replaceExisting) + { + if (replaceExisting) + { + ScriptNode *node = findChild(name, false); + if (node) + { + return node; + } + } + return new ScriptNode(this, name); + } + + ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive) + { + int indx, prevC, nextC; + int childCount = (int)m_children.size(); + + if (m_lastChildFound != -1) + { + //If possible, try checking the nodes neighboring the last successful search + //(often nodes searched for in sequence, so this will boost search speeds). + prevC = m_lastChildFound-1; if (prevC < 0) prevC = 0; else if (prevC >= childCount) prevC = childCount-1; + nextC = m_lastChildFound+1; if (nextC < 0) nextC = 0; else if (nextC >= childCount) nextC = childCount-1; + for (indx = prevC; indx <= nextC; ++indx) + { + ScriptNode *node = m_children[indx]; + if (node->m_name == name) + { + m_lastChildFound = indx; + return node; + } + } + + //If not found that way, search for the node from start to finish, avoiding the + //already searched area above. + for (indx = nextC + 1; indx < childCount; ++indx) + { + ScriptNode *node = m_children[indx]; + if (node->m_name == name) { + m_lastChildFound = indx; + return node; + } + } + for (indx = 0; indx < prevC; ++indx) + { + ScriptNode *node = m_children[indx]; + if (node->m_name == name) { + m_lastChildFound = indx; + return node; + } + } + } + else + { + //Search for the node from start to finish + for (indx = 0; indx < childCount; ++indx){ + ScriptNode *node = m_children[indx]; + if (node->m_name == name) { + m_lastChildFound = indx; + return node; + } + } + } + + //If not found, search child nodes (if recursive == true) + if (recursive) + { + for (indx = 0; indx < childCount; ++indx) + { + m_children[indx]->findChild(name, recursive); + } + } + + //Not found anywhere + return NULL; + } + + void ScriptNode::setParent(ScriptNode *newParent) + { + //Remove self from current parent + m_parent->m_children.erase(_iter); + + //Set new parent + m_parent = newParent; + + //Add self to new parent + m_parent->m_children.push_back(this); + _iter = --(m_parent->m_children.end()); + } +} diff --git a/extern/shiny/Main/ScriptLoader.hpp b/extern/shiny/Main/ScriptLoader.hpp new file mode 100644 index 0000000000..caf743bd22 --- /dev/null +++ b/extern/shiny/Main/ScriptLoader.hpp @@ -0,0 +1,134 @@ +#ifndef SH_CONFIG_LOADER_H__ +#define SH_CONFIG_LOADER_H__ + +#include +#include +#include +#include + +namespace sh +{ + class ScriptNode; + + /** + * @brief The base class of loaders that read Ogre style script files to get configuration and settings. + * Heavily inspired by: http://www.ogre3d.org/tikiwiki/All-purpose+script+parser + * ( "Non-ogre version") + */ + class ScriptLoader + { + public: + static void loadAllFiles(ScriptLoader* c, const std::string& path); + + ScriptLoader(const std::string& fileEnding); + virtual ~ScriptLoader(); + + std::string m_fileEnding; + + // For a line like + // entity animals/dog + // { + // ... + // } + // The type is "entity" and the name is "animals/dog" + // Or if animal/dog was not there then name is "" + ScriptNode *getConfigScript (const std::string &name); + + std::map getAllConfigScripts (); + + void parseScript(std::ifstream &stream); + + std::string m_currentFileName; + + protected: + + float m_LoadOrder; + // like "*.object" + + std::map m_scriptList; + + enum Token + { + TOKEN_Text, + TOKEN_NewLine, + TOKEN_OpenBrace, + TOKEN_CloseBrace, + TOKEN_EOF + }; + + Token tok, lastTok; + std::string tokVal; + + void _parseNodes(std::ifstream &stream, ScriptNode *parent); + void _nextToken(std::ifstream &stream); + void _skipNewLines(std::ifstream &stream); + + void clearScriptList(); + }; + + class ScriptNode + { + public: + ScriptNode(ScriptNode *parent, const std::string &name = "untitled"); + ~ScriptNode(); + + inline void setName(const std::string &name) + { + this->m_name = name; + } + + inline std::string &getName() + { + return m_name; + } + + inline void setValue(const std::string &value) + { + m_value = value; + } + + inline std::string &getValue() + { + return m_value; + } + + ScriptNode *addChild(const std::string &name = "untitled", bool replaceExisting = false); + ScriptNode *findChild(const std::string &name, bool recursive = false); + + inline std::vector &getChildren() + { + return m_children; + } + + inline ScriptNode *getChild(unsigned int index = 0) + { + assert(index < m_children.size()); + return m_children[index]; + } + + void setParent(ScriptNode *newParent); + + inline ScriptNode *getParent() + { + return m_parent; + } + + std::string m_fileName; + + + private: + std::string m_name; + std::string m_value; + std::vector m_children; + ScriptNode *m_parent; + + + int m_lastChildFound; //The last child node's index found with a call to findChild() + + std::vector::iterator _iter; + bool _removeSelf; + }; + +} + +#endif diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp new file mode 100644 index 0000000000..07ef8dfe28 --- /dev/null +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -0,0 +1,707 @@ +#include "ShaderInstance.hpp" + +#include +#include +#include + +#include +#include +#include + +#include + +#include "Preprocessor.hpp" +#include "Factory.hpp" +#include "ShaderSet.hpp" + +namespace +{ + std::string convertLang (sh::Language lang) + { + if (lang == sh::Language_CG) + return "SH_CG"; + else if (lang == sh::Language_HLSL) + return "SH_HLSL"; + else //if (lang == sh::Language_GLSL) + return "SH_GLSL"; + } + + char getComponent(int num) + { + if (num == 0) + return 'x'; + else if (num == 1) + return 'y'; + else if (num == 2) + return 'z'; + else if (num == 3) + return 'w'; + else + throw std::runtime_error("invalid component"); + } + + std::string getFloat(sh::Language lang, int num_components) + { + if (lang == sh::Language_CG || lang == sh::Language_HLSL) + return (num_components == 1) ? "float" : "float" + boost::lexical_cast(num_components); + else + return (num_components == 1) ? "float" : "vec" + boost::lexical_cast(num_components); + } + + bool isCmd (const std::string& source, size_t pos, const std::string& cmd) + { + return (source.size() >= pos + cmd.size() && source.substr(pos, cmd.size()) == cmd); + } + + void writeDebugFile (const std::string& content, const std::string& filename) + { + boost::filesystem::path full_path(boost::filesystem::current_path()); + std::ofstream of ((full_path / filename ).string().c_str() , std::ios_base::out); + of.write(content.c_str(), content.size()); + of.close(); + } +} + +namespace sh +{ + std::string Passthrough::expand_assign(std::string toAssign) + { + std::string res; + + int i = 0; + int current_passthrough = passthrough_number; + int current_component_left = component_start; + int current_component_right = 0; + int components_left = num_components; + int components_at_once; + while (i < num_components) + { + if (components_left + current_component_left <= 4) + components_at_once = components_left; + else + components_at_once = 4 - current_component_left; + + std::string componentStr = "."; + for (int j = 0; j < components_at_once; ++j) + componentStr += getComponent(j + current_component_left); + std::string componentStr2 = "."; + for (int j = 0; j < components_at_once; ++j) + componentStr2 += getComponent(j + current_component_right); + if (num_components == 1) + { + componentStr2 = ""; + } + res += "passthrough" + boost::lexical_cast(current_passthrough) + componentStr + " = " + toAssign + componentStr2; + + current_component_left += components_at_once; + current_component_right += components_at_once; + components_left -= components_at_once; + + i += components_at_once; + + if (components_left == 0) + { + // finished + return res; + } + else + { + // add semicolon to every instruction but the last + res += "; "; + } + + if (current_component_left == 4) + { + current_passthrough++; + current_component_left = 0; + } + } + throw std::runtime_error("expand_assign error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning + } + + std::string Passthrough::expand_receive() + { + std::string res; + + res += getFloat(lang, num_components) + "("; + + int i = 0; + int current_passthrough = passthrough_number; + int current_component = component_start; + int components_left = num_components; + while (i < num_components) + { + int components_at_once = std::min(components_left, 4 - current_component); + + std::string componentStr; + for (int j = 0; j < components_at_once; ++j) + componentStr += getComponent(j + current_component); + + res += "passthrough" + boost::lexical_cast(current_passthrough) + "." + componentStr; + + current_component += components_at_once; + + components_left -= components_at_once; + + i += components_at_once; + + if (components_left == 0) + { + // finished + return res + ")"; +; + } + else + { + // add comma to every variable but the last + res += ", "; + } + + if (current_component == 4) + { + current_passthrough++; + current_component = 0; + } + } + + throw std::runtime_error("expand_receive error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning + } + + // ------------------------------------------------------------------------------ + + void ShaderInstance::parse (std::string& source, PropertySetGet* properties) + { + size_t pos = 0; + while (true) + { + pos = source.find("@", pos); + if (pos == std::string::npos) + break; + + if (isCmd(source, pos, "@shProperty")) + { + std::vector args = extractMacroArguments (pos, source); + + size_t start = source.find("(", pos); + size_t end = source.find(")", pos); + std::string cmd = source.substr(pos+1, start-(pos+1)); + + std::string replaceValue; + if (cmd == "shPropertyBool") + { + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + bool val = retrieveValue(value, properties->getContext()).get(); + replaceValue = val ? "1" : "0"; + } + else if (cmd == "shPropertyNotBool") // same as above, but inverts the result + { + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + bool val = retrieveValue(value, properties->getContext()).get(); + replaceValue = val ? "0" : "1"; + } + else if (cmd == "shPropertyString") + { + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + replaceValue = retrieveValue(value, properties->getContext()).get(); + } + else if (cmd == "shPropertyEqual") + { + std::string propertyName = args[0]; + std::string comparedAgainst = args[1]; + std::string value = retrieveValue(properties->getProperty(propertyName), properties->getContext()).get(); + replaceValue = (value == comparedAgainst) ? "1" : "0"; + } + else + throw std::runtime_error ("unknown command \"" + cmd + "\""); + source.replace(pos, (end+1)-pos, replaceValue); + } + else if (isCmd(source, pos, "@shGlobalSetting")) + { + std::vector args = extractMacroArguments (pos, source); + + std::string cmd = source.substr(pos+1, source.find("(", pos)-(pos+1)); + std::string replaceValue; + if (cmd == "shGlobalSettingBool") + { + std::string settingName = args[0]; + std::string value = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); + replaceValue = (value == "true" || value == "1") ? "1" : "0"; + } + else if (cmd == "shGlobalSettingEqual") + { + std::string settingName = args[0]; + std::string comparedAgainst = args[1]; + std::string value = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); + replaceValue = (value == comparedAgainst) ? "1" : "0"; + } + else if (cmd == "shGlobalSettingString") + { + std::string settingName = args[0]; + replaceValue = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); + } + else + throw std::runtime_error ("unknown command \"" + cmd + "\""); + + source.replace(pos, (source.find(")", pos)+1)-pos, replaceValue); + } + else if (isCmd(source, pos, "@shForeach")) + { + + assert(source.find("@shEndForeach", pos) != std::string::npos); + size_t block_end = source.find("@shEndForeach", pos); + + // get the argument for parsing + size_t start = source.find("(", pos); + size_t end = start; + int brace_depth = 1; + while (brace_depth > 0) + { + ++end; + if (source[end] == '(') + ++brace_depth; + else if (source[end] == ')') + --brace_depth; + } + std::string arg = source.substr(start+1, end-(start+1)); + parse(arg, properties); + + int num = boost::lexical_cast(arg); + + // get the content of the inner block + std::string content = source.substr(end+1, block_end - (end+1)); + + // replace both outer and inner block with content of inner block num times + std::string replaceStr; + for (int i=0; i 0) + { + ++_end; + if (addStr[_end] == '(') + ++_brace_depth; + else if (addStr[_end] == ')') + --_brace_depth; + } + std::string arg = addStr.substr(_start+1, _end-(_start+1)); + parse(arg, properties); + + int offset = boost::lexical_cast (arg); + addStr.replace(pos2, (_end+1)-pos2, boost::lexical_cast(i+offset)); + } + else + { + addStr.replace(pos2, std::string("@shIterator").length(), boost::lexical_cast(i)); + } + } + + replaceStr += addStr; + } + source.replace(pos, (block_end+std::string("@shEndForeach").length())-pos, replaceStr); + } + else if (source.size() > pos+1) + ++pos; // skip + } + + } + + ShaderInstance::ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties) + : mName(name) + , mParent(parent) + , mSupported(true) + , mCurrentPassthrough(0) + , mCurrentComponent(0) + { + std::string source = mParent->getSource(); + int type = mParent->getType(); + std::string basePath = mParent->getBasePath(); + size_t pos; + + bool readCache = Factory::getInstance ().getReadSourceCache () && boost::filesystem::exists( + Factory::getInstance ().getCacheFolder () + "/" + mName) + && !mParent->isDirty (); + bool writeCache = Factory::getInstance ().getWriteSourceCache (); + + + if (readCache) + { + std::ifstream ifs( std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str() ); + std::stringstream ss; + ss << ifs.rdbuf(); + source = ss.str(); + } + else + { + std::vector definitions; + + if (mParent->getType() == GPT_Vertex) + definitions.push_back("SH_VERTEX_SHADER"); + else + definitions.push_back("SH_FRAGMENT_SHADER"); + definitions.push_back(convertLang(Factory::getInstance().getCurrentLanguage())); + + parse(source, properties); + + if (Factory::getInstance ().getShaderDebugOutputEnabled ()) + writeDebugFile(source, name + ".pre"); + else + { + #ifdef SHINY_WRITE_SHADER_DEBUG + writeDebugFile(source, name + ".pre"); + #endif + } + + // why do we need our own preprocessor? there are several custom commands available in the shader files + // (for example for binding uniforms to properties or auto constants) - more below. it is important that these + // commands are _only executed if the specific code path actually "survives" the compilation. + // thus, we run the code through a preprocessor first to remove the parts that are unused because of + // unmet #if conditions (or other preprocessor directives). + source = Preprocessor::preprocess(source, basePath, definitions, name); + + // parse counter + std::map counters; + while (true) + { + pos = source.find("@shCounter"); + if (pos == std::string::npos) + break; + + size_t end = source.find(")", pos); + + std::vector args = extractMacroArguments (pos, source); + assert(args.size()); + + int index = boost::lexical_cast(args[0]); + + if (counters.find(index) == counters.end()) + counters[index] = 0; + + source.replace(pos, (end+1)-pos, boost::lexical_cast(counters[index]++)); + } + + // parse passthrough declarations + while (true) + { + pos = source.find("@shAllocatePassthrough"); + if (pos == std::string::npos) + break; + + if (mCurrentPassthrough > 7) + throw std::runtime_error ("too many passthrough's requested (max 8)"); + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() == 2); + + size_t end = source.find(")", pos); + + Passthrough passthrough; + + passthrough.num_components = boost::lexical_cast(args[0]); + assert (passthrough.num_components != 0); + + std::string passthroughName = args[1]; + passthrough.lang = Factory::getInstance().getCurrentLanguage (); + passthrough.component_start = mCurrentComponent; + passthrough.passthrough_number = mCurrentPassthrough; + + mPassthroughMap[passthroughName] = passthrough; + + mCurrentComponent += passthrough.num_components; + if (mCurrentComponent > 3) + { + mCurrentComponent -= 4; + ++mCurrentPassthrough; + } + + source.erase(pos, (end+1)-pos); + } + + // passthrough assign + while (true) + { + pos = source.find("@shPassthroughAssign"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() == 2); + + size_t end = source.find(")", pos); + + std::string passthroughName = args[0]; + std::string assignTo = args[1]; + + assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end()); + Passthrough& p = mPassthroughMap[passthroughName]; + + source.replace(pos, (end+1)-pos, p.expand_assign(assignTo)); + } + + // passthrough receive + while (true) + { + pos = source.find("@shPassthroughReceive"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() == 1); + + size_t end = source.find(")", pos); + std::string passthroughName = args[0]; + + assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end()); + Passthrough& p = mPassthroughMap[passthroughName]; + + source.replace(pos, (end+1)-pos, p.expand_receive()); + } + + // passthrough vertex outputs + while (true) + { + pos = source.find("@shPassthroughVertexOutputs"); + if (pos == std::string::npos) + break; + + std::string result; + for (int i = 0; i < mCurrentPassthrough+1; ++i) + { + // not using newlines here, otherwise the line numbers reported by compiler would be messed up.. + if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL) + result += ", out float4 passthrough" + boost::lexical_cast(i) + " : TEXCOORD" + boost::lexical_cast(i); + + /* + else + result += "out vec4 passthrough" + boost::lexical_cast(i) + "; "; + */ + else + result += "varying vec4 passthrough" + boost::lexical_cast(i) + "; "; + } + + source.replace(pos, std::string("@shPassthroughVertexOutputs").length(), result); + } + + // passthrough fragment inputs + while (true) + { + pos = source.find("@shPassthroughFragmentInputs"); + if (pos == std::string::npos) + break; + + std::string result; + for (int i = 0; i < mCurrentPassthrough+1; ++i) + { + // not using newlines here, otherwise the line numbers reported by compiler would be messed up.. + if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL) + result += ", in float4 passthrough" + boost::lexical_cast(i) + " : TEXCOORD" + boost::lexical_cast(i); + /* + else + result += "in vec4 passthrough" + boost::lexical_cast(i) + "; "; + */ + else + result += "varying vec4 passthrough" + boost::lexical_cast(i) + "; "; + } + + source.replace(pos, std::string("@shPassthroughFragmentInputs").length(), result); + } + } + + // save to cache _here_ - we want to preserve some macros + if (writeCache && !readCache) + { + std::ofstream of (std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str(), std::ios_base::out); + of.write(source.c_str(), source.size()); + of.close(); + } + + + // parse shared parameters + while (true) + { + pos = source.find("@shSharedParameter"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size()); + + size_t end = source.find(")", pos); + + mSharedParameters.push_back(args[0]); + + source.erase(pos, (end+1)-pos); + } + + // parse auto constants + typedef std::map< std::string, std::pair > AutoConstantMap; + AutoConstantMap autoConstants; + while (true) + { + pos = source.find("@shAutoConstant"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() >= 2); + + size_t end = source.find(")", pos); + + std::string autoConstantName, uniformName; + std::string extraData; + + uniformName = args[0]; + autoConstantName = args[1]; + if (args.size() > 2) + extraData = args[2]; + + autoConstants[uniformName] = std::make_pair(autoConstantName, extraData); + + source.erase(pos, (end+1)-pos); + } + + // parse uniform properties + while (true) + { + pos = source.find("@shUniformProperty"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() == 2); + + size_t start = source.find("(", pos); + size_t end = source.find(")", pos); + std::string cmd = source.substr(pos, start-pos); + + ValueType vt; + if (cmd == "@shUniformProperty4f") + vt = VT_Vector4; + else if (cmd == "@shUniformProperty3f") + vt = VT_Vector3; + else if (cmd == "@shUniformProperty2f") + vt = VT_Vector2; + else if (cmd == "@shUniformProperty1f") + vt = VT_Float; + else if (cmd == "@shUniformPropertyInt") + vt = VT_Int; + else + throw std::runtime_error ("unsupported command \"" + cmd + "\""); + + + std::string propertyName, uniformName; + uniformName = args[0]; + propertyName = args[1]; + mUniformProperties[uniformName] = std::make_pair(propertyName, vt); + + source.erase(pos, (end+1)-pos); + } + + // parse texture samplers used + while (true) + { + pos = source.find("@shUseSampler"); + if (pos == std::string::npos) + break; + + size_t end = source.find(")", pos); + + mUsedSamplers.push_back(extractMacroArguments (pos, source)[0]); + source.erase(pos, (end+1)-pos); + } + + // convert any left-over @'s to # + boost::algorithm::replace_all(source, "@", "#"); + + Platform* platform = Factory::getInstance().getPlatform(); + + std::string profile; + if (Factory::getInstance ().getCurrentLanguage () == Language_CG) + profile = mParent->getCgProfile (); + else if (Factory::getInstance ().getCurrentLanguage () == Language_HLSL) + profile = mParent->getHlslProfile (); + + + if (type == GPT_Vertex) + mProgram = boost::shared_ptr(platform->createGpuProgram(GPT_Vertex, "", mName, profile, source, Factory::getInstance().getCurrentLanguage())); + else if (type == GPT_Fragment) + mProgram = boost::shared_ptr(platform->createGpuProgram(GPT_Fragment, "", mName, profile, source, Factory::getInstance().getCurrentLanguage())); + + + if (Factory::getInstance ().getShaderDebugOutputEnabled ()) + writeDebugFile(source, name); + else + { +#ifdef SHINY_WRITE_SHADER_DEBUG + writeDebugFile(source, name); +#endif + } + + if (!mProgram->getSupported()) + { + std::cerr << " Full source code below: \n" << source << std::endl; + mSupported = false; + return; + } + + // set auto constants + for (AutoConstantMap::iterator it = autoConstants.begin(); it != autoConstants.end(); ++it) + { + mProgram->setAutoConstant(it->first, it->second.first, it->second.second); + } + } + + std::string ShaderInstance::getName () + { + return mName; + } + + bool ShaderInstance::getSupported () const + { + return mSupported; + } + + std::vector ShaderInstance::getUsedSamplers() + { + return mUsedSamplers; + } + + void ShaderInstance::setUniformParameters (boost::shared_ptr pass, PropertySetGet* properties) + { + for (UniformMap::iterator it = mUniformProperties.begin(); it != mUniformProperties.end(); ++it) + { + pass->setGpuConstant(mParent->getType(), it->first, it->second.second, properties->getProperty(it->second.first), properties->getContext()); + } + } + + std::vector ShaderInstance::extractMacroArguments (size_t pos, const std::string& source) + { + size_t start = source.find("(", pos); + size_t end = source.find(")", pos); + std::string args = source.substr(start+1, end-(start+1)); + std::vector results; + boost::algorithm::split(results, args, boost::is_any_of(",")); + std::for_each(results.begin(), results.end(), + boost::bind(&boost::trim, + _1, std::locale() )); + return results; + } +} diff --git a/extern/shiny/Main/ShaderInstance.hpp b/extern/shiny/Main/ShaderInstance.hpp new file mode 100644 index 0000000000..76326ce0c3 --- /dev/null +++ b/extern/shiny/Main/ShaderInstance.hpp @@ -0,0 +1,71 @@ +#ifndef SH_SHADERINSTANCE_H +#define SH_SHADERINSTANCE_H + +#include + +#include "Platform.hpp" + +namespace sh +{ + class ShaderSet; + + typedef std::map< std::string, std::pair > UniformMap; + + struct Passthrough + { + Language lang; ///< language to generate for + + int num_components; ///< e.g. 4 for a float4 + + int passthrough_number; + int component_start; ///< 0 = x + + std::string expand_assign(std::string assignTo); + std::string expand_receive(); + }; + typedef std::map PassthroughMap; + + /** + * @brief A specific instance of a \a ShaderSet with a deterministic shader source + */ + class ShaderInstance + { + public: + ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties); + + std::string getName(); + + bool getSupported () const; + + std::vector getUsedSamplers(); + std::vector getSharedParameters() { return mSharedParameters; } + + void setUniformParameters (boost::shared_ptr pass, PropertySetGet* properties); + + private: + boost::shared_ptr mProgram; + std::string mName; + ShaderSet* mParent; + bool mSupported; ///< shader compilation was sucessful? + + std::vector mUsedSamplers; + ///< names of the texture samplers that are used by this shader + + std::vector mSharedParameters; + + UniformMap mUniformProperties; + ///< uniforms that this depends on, and their property names / value-types + /// @note this lists shared uniform parameters as well + + int mCurrentPassthrough; ///< 0 - x + int mCurrentComponent; ///< 0:x, 1:y, 2:z, 3:w + + PassthroughMap mPassthroughMap; + + std::vector extractMacroArguments (size_t pos, const std::string& source); ///< take a macro invocation and return vector of arguments + + void parse (std::string& source, PropertySetGet* properties); + }; +} + +#endif diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp new file mode 100644 index 0000000000..2702ece194 --- /dev/null +++ b/extern/shiny/Main/ShaderSet.cpp @@ -0,0 +1,172 @@ +#include "ShaderSet.hpp" + +#include +#include + +#include +#include +#include + +#include "Factory.hpp" + +namespace sh +{ + ShaderSet::ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, + const std::string& name, PropertySetGet* globalSettingsPtr) + : mBasePath(basePath) + , mName(name) + , mCgProfile(cgProfile) + , mHlslProfile(hlslProfile) + , mIsDirty(false) + { + if (type == "vertex") + mType = GPT_Vertex; + else // if (type == "fragment") + mType = GPT_Fragment; + + std::ifstream stream(sourceFile.c_str(), std::ifstream::in); + std::stringstream buffer; + + buffer << stream.rdbuf(); + stream.close(); + mSource = buffer.str(); + parse(); + } + + void ShaderSet::parse() + { + std::string currentToken; + bool tokenIsRecognized = false; + bool isInBraces = false; + for (std::string::const_iterator it = mSource.begin(); it != mSource.end(); ++it) + { + char c = *it; + if (((c == ' ') && !isInBraces) || (c == '\n') || + ( ((c == '(') || (c == ')')) + && !tokenIsRecognized)) + { + if (tokenIsRecognized) + { + if (boost::starts_with(currentToken, "@shGlobalSetting")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); + size_t start = currentToken.find('(')+1; + mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start)); + } + else if (boost::starts_with(currentToken, "@shPropertyEqual")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos) + && (currentToken.find(',') != std::string::npos)); + size_t start = currentToken.find('(')+1; + size_t end = currentToken.find(','); + mProperties.push_back(currentToken.substr(start, end-start)); + } + else if (boost::starts_with(currentToken, "@shProperty")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); + size_t start = currentToken.find('(')+1; + std::string propertyName = currentToken.substr(start, currentToken.find(')')-start); + // if the property name is constructed dynamically (e.g. through an iterator) then there is nothing we can do + if (propertyName.find("@") == std::string::npos) + mProperties.push_back(propertyName); + } + } + + currentToken = ""; + } + else + { + if (currentToken == "") + { + if (c == '@') + tokenIsRecognized = true; + else + tokenIsRecognized = false; + } + else + { + if (c == '@') + { + // ouch, there are nested macros + // ( for example @shForeach(@shPropertyString(foobar)) ) + currentToken = ""; + } + } + + if (c == '(' && tokenIsRecognized) + isInBraces = true; + else if (c == ')' && tokenIsRecognized) + isInBraces = false; + + currentToken += c; + + } + } + } + + ShaderInstance* ShaderSet::getInstance (PropertySetGet* properties) + { + size_t h = buildHash (properties); + if (std::find(mFailedToCompile.begin(), mFailedToCompile.end(), h) != mFailedToCompile.end()) + return NULL; + if (mInstances.find(h) == mInstances.end()) + { + ShaderInstance newInstance(this, mName + "_" + boost::lexical_cast(h), properties); + if (!newInstance.getSupported()) + { + mFailedToCompile.push_back(h); + return NULL; + } + mInstances.insert(std::make_pair(h, newInstance)); + } + return &mInstances.find(h)->second; + } + + size_t ShaderSet::buildHash (PropertySetGet* properties) + { + size_t seed = 0; + PropertySetGet* currentGlobalSettings = getCurrentGlobalSettings (); + + for (std::vector::iterator it = mProperties.begin(); it != mProperties.end(); ++it) + { + std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); + boost::hash_combine(seed, v); + } + for (std::vector ::iterator it = mGlobalSettings.begin(); it != mGlobalSettings.end(); ++it) + { + boost::hash_combine(seed, retrieveValue(currentGlobalSettings->getProperty(*it), NULL).get()); + } + boost::hash_combine(seed, static_cast(Factory::getInstance().getCurrentLanguage())); + return seed; + } + + PropertySetGet* ShaderSet::getCurrentGlobalSettings() const + { + return Factory::getInstance ().getCurrentGlobalSettings (); + } + + std::string ShaderSet::getBasePath() const + { + return mBasePath; + } + + std::string ShaderSet::getSource() const + { + return mSource; + } + + std::string ShaderSet::getCgProfile() const + { + return mCgProfile; + } + + std::string ShaderSet::getHlslProfile() const + { + return mHlslProfile; + } + + int ShaderSet::getType() const + { + return mType; + } +} diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp new file mode 100644 index 0000000000..776750598a --- /dev/null +++ b/extern/shiny/Main/ShaderSet.hpp @@ -0,0 +1,71 @@ +#ifndef SH_SHADERSET_H +#define SH_SHADERSET_H + +#include +#include +#include + +#include "ShaderInstance.hpp" + +namespace sh +{ + class PropertySetGet; + + typedef std::map ShaderInstanceMap; + + /** + * @brief Contains possible shader permutations of a single uber-shader (represented by one source file) + */ + class ShaderSet + { + public: + ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, + const std::string& name, PropertySetGet* globalSettingsPtr); + + /// Retrieve a shader instance for the given properties. \n + /// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n + /// Otherwise, creates a new \a ShaderInstance (i.e. compiles a new shader). \n + /// Might also return NULL if the shader failed to compile. \n + /// @note Only the properties that actually affect the shader source are taken into consideration here, + /// so it does not matter if you pass any extra properties that the shader does not care about. + ShaderInstance* getInstance (PropertySetGet* properties); + + void markDirty() { mIsDirty = true; } + ///< Signals that the cache is out of date, and thus should not be used this time + + private: + PropertySetGet* getCurrentGlobalSettings() const; + std::string getBasePath() const; + std::string getSource() const; + std::string getCgProfile() const; + std::string getHlslProfile() const; + int getType() const; + + bool isDirty() { return mIsDirty; } + + friend class ShaderInstance; + + bool mIsDirty; + + private: + GpuProgramType mType; + std::string mSource; + std::string mBasePath; + std::string mCgProfile; + std::string mHlslProfile; + std::string mName; + + std::vector mFailedToCompile; + + std::vector mGlobalSettings; ///< names of the global settings that affect the shader source + std::vector mProperties; ///< names of the per-material properties that affect the shader source + + ShaderInstanceMap mInstances; ///< maps permutation ID (generated from the properties) to \a ShaderInstance + + void parse(); ///< find out which properties and global settings affect the shader source + + size_t buildHash (PropertySetGet* properties); + }; +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp b/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp new file mode 100644 index 0000000000..fe5aa2fe77 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp @@ -0,0 +1,70 @@ +#include + +#include "OgreGpuProgram.hpp" + +#include + +#include +#include +#include + +namespace sh +{ + OgreGpuProgram::OgreGpuProgram( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, const std::string& lang, + const std::string& resourceGroup) + : GpuProgram() + { + Ogre::HighLevelGpuProgramManager& mgr = Ogre::HighLevelGpuProgramManager::getSingleton(); + assert (mgr.getByName(name).isNull() && "Vertex program already exists"); + + Ogre::GpuProgramType t; + if (type == GPT_Vertex) + t = Ogre::GPT_VERTEX_PROGRAM; + else + t = Ogre::GPT_FRAGMENT_PROGRAM; + + mProgram = mgr.createProgram(name, resourceGroup, lang, t); + if (lang != "glsl") + mProgram->setParameter("entry_point", "main"); + + if (lang == "hlsl") + mProgram->setParameter("target", profile); + else if (lang == "cg") + mProgram->setParameter("profiles", profile); + + mProgram->setSource(source); + mProgram->load(); + + if (mProgram.isNull() || !mProgram->isSupported()) + std::cerr << "Failed to compile shader \"" << name << "\". Consider the OGRE log for more information." << std::endl; + } + + bool OgreGpuProgram::getSupported() + { + return (!mProgram.isNull() && mProgram->isSupported()); + } + + void OgreGpuProgram::setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo) + { + assert (!mProgram.isNull() && mProgram->isSupported()); + const Ogre::GpuProgramParameters::AutoConstantDefinition* d = Ogre::GpuProgramParameters::getAutoConstantDefinition(autoConstantName); + + if (!d) + throw std::runtime_error ("can't find auto constant with name \"" + autoConstantName + "\""); + Ogre::GpuProgramParameters::AutoConstantType t = d->acType; + + // this simplifies debugging for CG a lot. + mProgram->getDefaultParameters()->setIgnoreMissingParams(true); + + if (d->dataType == Ogre::GpuProgramParameters::ACDT_NONE) + mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, 0); + else if (d->dataType == Ogre::GpuProgramParameters::ACDT_INT) + mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, extraInfo == "" ? 0 : boost::lexical_cast(extraInfo)); + else if (d->dataType == Ogre::GpuProgramParameters::ACDT_REAL) + mProgram->getDefaultParameters()->setNamedAutoConstantReal (name, t, extraInfo == "" ? 0.f : boost::lexical_cast(extraInfo)); + } +} diff --git a/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp b/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp new file mode 100644 index 0000000000..42673ed9b4 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp @@ -0,0 +1,31 @@ +#ifndef SH_OGREGPUPROGRAM_H +#define SH_OGREGPUPROGRAM_H + +#include + +#include + +#include "../../Main/Platform.hpp" + +namespace sh +{ + class OgreGpuProgram : public GpuProgram + { + public: + OgreGpuProgram ( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, const std::string& lang, + const std::string& resourceGroup); + + virtual bool getSupported(); + + virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = ""); + + private: + Ogre::HighLevelGpuProgramPtr mProgram; + }; +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.cpp b/extern/shiny/Platforms/Ogre/OgreMaterial.cpp new file mode 100644 index 0000000000..4a550b8bff --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreMaterial.cpp @@ -0,0 +1,99 @@ +#include "OgreMaterial.hpp" + +#include +#include +#include + +#include "OgrePass.hpp" +#include "OgreMaterialSerializer.hpp" +#include "OgrePlatform.hpp" + +namespace sh +{ + static const std::string sDefaultTechniqueName = "SH_DefaultTechnique"; + + OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup) + : Material() + { + assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists"); + mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup); + mMaterial->removeAllTechniques(); + mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); + mMaterial->compile(); + } + + OgreMaterial::~OgreMaterial() + { + Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); + } + + boost::shared_ptr OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex) + { + return boost::shared_ptr (new OgrePass (this, configuration, lodIndex)); + } + + void OgreMaterial::removeAll () + { + mMaterial->removeAllTechniques(); + mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); + mMaterial->compile(); + } + + void OgreMaterial::setLodLevels (const std::string& lodLevels) + { + OgreMaterialSerializer& s = OgrePlatform::getSerializer(); + + s.setMaterialProperty ("lod_values", lodLevels, mMaterial); + } + + bool OgreMaterial::createConfiguration (const std::string& name, unsigned short lodIndex) + { + for (int i=0; igetNumTechniques(); ++i) + { + if (mMaterial->getTechnique(i)->getSchemeName() == name && mMaterial->getTechnique(i)->getLodIndex() == lodIndex) + return false; + } + + Ogre::Technique* t = mMaterial->createTechnique(); + t->setSchemeName (name); + t->setLodIndex (lodIndex); + if (mShadowCasterMaterial != "") + t->setShadowCasterMaterial(mShadowCasterMaterial); + + mMaterial->compile(); + + return true; + } + + Ogre::MaterialPtr OgreMaterial::getOgreMaterial () + { + return mMaterial; + } + + Ogre::Technique* OgreMaterial::getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex) + { + for (int i=0; igetNumTechniques(); ++i) + { + if (mMaterial->getTechnique(i)->getSchemeName() == configurationName && mMaterial->getTechnique(i)->getLodIndex() == lodIndex) + { + return mMaterial->getTechnique(i); + } + } + + // Prepare and throw error message + std::stringstream message; + message << "Could not find configurationName '" << configurationName + << "' and lodIndex " << lodIndex; + + throw std::runtime_error(message.str()); + } + + void OgreMaterial::setShadowCasterMaterial (const std::string& name) + { + mShadowCasterMaterial = name; + for (int i=0; igetNumTechniques(); ++i) + { + mMaterial->getTechnique(i)->setShadowCasterMaterial(mShadowCasterMaterial); + } + } +} diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.hpp b/extern/shiny/Platforms/Ogre/OgreMaterial.hpp new file mode 100644 index 0000000000..bec23f0b6f --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreMaterial.hpp @@ -0,0 +1,38 @@ +#ifndef SH_OGREMATERIAL_H +#define SH_OGREMATERIAL_H + +#include + +#include + +#include "../../Main/Platform.hpp" + +namespace sh +{ + class OgreMaterial : public Material + { + public: + OgreMaterial (const std::string& name, const std::string& resourceGroup); + virtual ~OgreMaterial(); + + virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex); + virtual bool createConfiguration (const std::string& name, unsigned short lodIndex); + + virtual void removeAll (); + + Ogre::MaterialPtr getOgreMaterial(); + + virtual void setLodLevels (const std::string& lodLevels); + + Ogre::Technique* getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex = 0); + + virtual void setShadowCasterMaterial (const std::string& name); + + private: + Ogre::MaterialPtr mMaterial; + + std::string mShadowCasterMaterial; + }; +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp new file mode 100644 index 0000000000..9f57c7b441 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp @@ -0,0 +1,67 @@ +#include "OgreMaterialSerializer.hpp" + +namespace sh +{ + void OgreMaterialSerializer::reset() + { + mScriptContext.section = Ogre::MSS_NONE; + mScriptContext.material.setNull(); + mScriptContext.technique = 0; + mScriptContext.pass = 0; + mScriptContext.textureUnit = 0; + mScriptContext.program.setNull(); + mScriptContext.lineNo = 0; + mScriptContext.filename.clear(); + mScriptContext.techLev = -1; + mScriptContext.passLev = -1; + mScriptContext.stateLev = -1; + } + + bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass) + { + reset(); + + mScriptContext.section = Ogre::MSS_PASS; + mScriptContext.pass = pass; + + if (mPassAttribParsers.find (param) == mPassAttribParsers.end()) + return false; + else + { + mPassAttribParsers.find(param)->second(value, mScriptContext); + return true; + } + } + + bool OgreMaterialSerializer::setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t) + { + reset(); + + mScriptContext.section = Ogre::MSS_TEXTUREUNIT; + mScriptContext.textureUnit = t; + + if (mTextureUnitAttribParsers.find (param) == mTextureUnitAttribParsers.end()) + return false; + else + { + mTextureUnitAttribParsers.find(param)->second(value, mScriptContext); + return true; + } + } + + bool OgreMaterialSerializer::setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m) + { + reset(); + + mScriptContext.section = Ogre::MSS_MATERIAL; + mScriptContext.material = m; + + if (mMaterialAttribParsers.find (param) == mMaterialAttribParsers.end()) + return false; + else + { + mMaterialAttribParsers.find(param)->second(value, mScriptContext); + return true; + } + } +} diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp new file mode 100644 index 0000000000..acfc5a362f --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp @@ -0,0 +1,29 @@ +#ifndef SH_OGREMATERIALSERIALIZER_H +#define SH_OGREMATERIALSERIALIZER_H + +#include + +namespace Ogre +{ + class Pass; +} + +namespace sh +{ + /** + * @brief This class allows me to let Ogre handle the pass & texture unit properties + */ + class OgreMaterialSerializer : public Ogre::MaterialSerializer + { + public: + bool setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass); + bool setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t); + bool setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m); + + private: + void reset(); + }; + +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp new file mode 100644 index 0000000000..8cfaae0788 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgrePass.cpp @@ -0,0 +1,128 @@ +#include + +#include "OgrePass.hpp" + +#include +#include + +#include "OgreTextureUnitState.hpp" +#include "OgreGpuProgram.hpp" +#include "OgreMaterial.hpp" +#include "OgreMaterialSerializer.hpp" +#include "OgrePlatform.hpp" + +namespace sh +{ + OgrePass::OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex) + : Pass() + { + Ogre::Technique* t = parent->getOgreTechniqueForConfiguration(configuration, lodIndex); + mPass = t->createPass(); + } + + boost::shared_ptr OgrePass::createTextureUnitState () + { + return boost::shared_ptr (new OgreTextureUnitState (this)); + } + + void OgrePass::assignProgram (GpuProgramType type, const std::string& name) + { + if (type == GPT_Vertex) + mPass->setVertexProgram (name); + else if (type == GPT_Fragment) + mPass->setFragmentProgram (name); + else + throw std::runtime_error("unsupported GpuProgramType"); + } + + Ogre::Pass* OgrePass::getOgrePass () + { + return mPass; + } + + bool OgrePass::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) + { + if (((typeid(*value) == typeid(StringValue)) || typeid(*value) == typeid(LinkedValue)) + && retrieveValue(value, context).get() == "default") + return true; + + if (name == "vertex_program") + return true; // handled already + else if (name == "fragment_program") + return true; // handled already + else if (name == "ffp_vertex_colour_ambient") + { + bool enabled = retrieveValue(value, context).get(); + // fixed-function vertex colour tracking + mPass->setVertexColourTracking(enabled ? Ogre::TVC_AMBIENT : Ogre::TVC_NONE); + return true; + } + else + { + OgreMaterialSerializer& s = OgrePlatform::getSerializer(); + + return s.setPassProperty (name, retrieveValue(value, context).get(), mPass); + } + } + + void OgrePass::setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) + { + Ogre::GpuProgramParametersSharedPtr params; + if (type == GPT_Vertex) + { + if (!mPass->hasVertexProgram ()) + return; + params = mPass->getVertexProgramParameters(); + } + else if (type == GPT_Fragment) + { + if (!mPass->hasFragmentProgram ()) + return; + params = mPass->getFragmentProgramParameters(); + } + + if (vt == VT_Float) + params->setNamedConstant (name, retrieveValue(value, context).get()); + else if (vt == VT_Int) + params->setNamedConstant (name, retrieveValue(value, context).get()); + else if (vt == VT_Vector4) + { + Vector4 v = retrieveValue(value, context); + params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, v.mW)); + } + else if (vt == VT_Vector3) + { + Vector3 v = retrieveValue(value, context); + params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, 1.0)); + } + else if (vt == VT_Vector2) + { + Vector2 v = retrieveValue(value, context); + params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, 1.0, 1.0)); + } + else + throw std::runtime_error ("unsupported constant type"); + } + + void OgrePass::addSharedParameter (int type, const std::string& name) + { + Ogre::GpuProgramParametersSharedPtr params; + if (type == GPT_Vertex) + params = mPass->getVertexProgramParameters(); + else if (type == GPT_Fragment) + params = mPass->getFragmentProgramParameters(); + + params->addSharedParameters (name); + } + + void OgrePass::setTextureUnitIndex (int programType, const std::string& name, int index) + { + Ogre::GpuProgramParametersSharedPtr params; + if (programType == GPT_Vertex) + params = mPass->getVertexProgramParameters(); + else if (programType == GPT_Fragment) + params = mPass->getFragmentProgramParameters(); + + params->setNamedConstant(name, index); + } +} diff --git a/extern/shiny/Platforms/Ogre/OgrePass.hpp b/extern/shiny/Platforms/Ogre/OgrePass.hpp new file mode 100644 index 0000000000..da67a1a2a5 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgrePass.hpp @@ -0,0 +1,35 @@ +#ifndef SH_OGREPASS_H +#define SH_OGREPASS_H + +#include + +#include "../../Main/Platform.hpp" + +namespace sh +{ + class OgreMaterial; + + class OgrePass : public Pass + { + public: + OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex); + + virtual boost::shared_ptr createTextureUnitState (); + virtual void assignProgram (GpuProgramType type, const std::string& name); + + Ogre::Pass* getOgrePass(); + + virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context); + + virtual void addSharedParameter (int type, const std::string& name); + virtual void setTextureUnitIndex (int programType, const std::string& name, int index); + + private: + Ogre::Pass* mPass; + + protected: + virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context); + }; +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp new file mode 100644 index 0000000000..357949402f --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp @@ -0,0 +1,174 @@ +#include + +#include "OgrePlatform.hpp" + +#include +#include +#include + +#include "OgreMaterial.hpp" +#include "OgreGpuProgram.hpp" +#include "OgreMaterialSerializer.hpp" + +#include "../../Main/MaterialInstance.hpp" +#include "../../Main/Factory.hpp" + +namespace +{ + std::string convertLang (sh::Language lang) + { + if (lang == sh::Language_CG) + return "cg"; + else if (lang == sh::Language_HLSL) + return "hlsl"; + else if (lang == sh::Language_GLSL) + return "glsl"; + throw std::runtime_error ("invalid language, valid are: cg, hlsl, glsl"); + } +} + +namespace sh +{ + OgreMaterialSerializer* OgrePlatform::sSerializer = 0; + + OgrePlatform::OgrePlatform(const std::string& resourceGroupName, const std::string& basePath) + : Platform(basePath) + , mResourceGroup(resourceGroupName) + { + Ogre::MaterialManager::getSingleton().addListener(this); + + if (supportsShaderSerialization()) + Ogre::GpuProgramManager::getSingletonPtr()->setSaveMicrocodesToCache(true); + + sSerializer = new OgreMaterialSerializer(); + } + + OgreMaterialSerializer& OgrePlatform::getSerializer() + { + assert(sSerializer); + return *sSerializer; + } + + OgrePlatform::~OgrePlatform () + { + delete sSerializer; + } + + bool OgrePlatform::isProfileSupported (const std::string& profile) + { + return Ogre::GpuProgramManager::getSingleton().isSyntaxSupported(profile); + } + + bool OgrePlatform::supportsShaderSerialization () + { + // Not very reliable in OpenGL mode (requires extension), and somehow doesn't work on linux even if the extension is present + return Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") == std::string::npos; + } + + bool OgrePlatform::supportsMaterialQueuedListener () + { + return true; + } + + boost::shared_ptr OgrePlatform::createMaterial (const std::string& name) + { + OgreMaterial* material = new OgreMaterial(name, mResourceGroup); + return boost::shared_ptr (material); + } + + boost::shared_ptr OgrePlatform::createGpuProgram ( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, Language lang) + { + OgreGpuProgram* prog = new OgreGpuProgram (type, compileArguments, name, profile, source, convertLang(lang), mResourceGroup); + return boost::shared_ptr (static_cast(prog)); + } + + Ogre::Technique* OgrePlatform::handleSchemeNotFound ( + unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, + unsigned short lodIndex, const Ogre::Renderable *rend) + { + MaterialInstance* m = fireMaterialRequested(originalMaterial->getName(), schemeName, lodIndex); + if (m) + { + OgreMaterial* _m = static_cast(m->getMaterial()); + return _m->getOgreTechniqueForConfiguration (schemeName, lodIndex); + } + else + return 0; // material does not belong to us + } + + void OgrePlatform::serializeShaders (const std::string& file) + { + std::fstream output; + output.open(file.c_str(), std::ios::out | std::ios::binary); + Ogre::DataStreamPtr shaderCache (OGRE_NEW Ogre::FileStreamDataStream(file, &output, false)); + Ogre::GpuProgramManager::getSingleton().saveMicrocodeCache(shaderCache); + } + + void OgrePlatform::deserializeShaders (const std::string& file) + { + std::ifstream inp; + inp.open(file.c_str(), std::ios::in | std::ios::binary); + Ogre::DataStreamPtr shaderCache(OGRE_NEW Ogre::FileStreamDataStream(file, &inp, false)); + Ogre::GpuProgramManager::getSingleton().loadMicrocodeCache(shaderCache); + } + + void OgrePlatform::setSharedParameter (const std::string& name, PropertyValuePtr value) + { + Ogre::GpuSharedParametersPtr params; + if (mSharedParameters.find(name) == mSharedParameters.end()) + { + params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name); + Ogre::GpuConstantType type; + if (typeid(*value) == typeid(Vector4)) + type = Ogre::GCT_FLOAT4; + else if (typeid(*value) == typeid(Vector3)) + type = Ogre::GCT_FLOAT3; + else if (typeid(*value) == typeid(Vector2)) + type = Ogre::GCT_FLOAT2; + else if (typeid(*value) == typeid(FloatValue)) + type = Ogre::GCT_FLOAT1; + else if (typeid(*value) == typeid(IntValue)) + type = Ogre::GCT_INT1; + else + assert(0); + params->addConstantDefinition(name, type); + mSharedParameters[name] = params; + } + else + params = mSharedParameters.find(name)->second; + + Ogre::Vector4 v (1.0, 1.0, 1.0, 1.0); + if (typeid(*value) == typeid(Vector4)) + { + Vector4 vec = retrieveValue(value, NULL); + v.x = vec.mX; + v.y = vec.mY; + v.z = vec.mZ; + v.w = vec.mW; + } + else if (typeid(*value) == typeid(Vector3)) + { + Vector3 vec = retrieveValue(value, NULL); + v.x = vec.mX; + v.y = vec.mY; + v.z = vec.mZ; + } + else if (typeid(*value) == typeid(Vector2)) + { + Vector2 vec = retrieveValue(value, NULL); + v.x = vec.mX; + v.y = vec.mY; + } + else if (typeid(*value) == typeid(FloatValue)) + v.x = retrieveValue(value, NULL).get(); + else if (typeid(*value) == typeid(IntValue)) + v.x = static_cast(retrieveValue(value, NULL).get()); + else + throw std::runtime_error ("unsupported property type for shared parameter \"" + name + "\""); + params->setNamedConstant(name, v); + } +} diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.hpp b/extern/shiny/Platforms/Ogre/OgrePlatform.hpp new file mode 100644 index 0000000000..d115c46bb4 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgrePlatform.hpp @@ -0,0 +1,72 @@ +#ifndef SH_OGREPLATFORM_H +#define SH_OGREPLATFORM_H + +/** + * @addtogroup Platforms + * @{ + */ + +/** + * @addtogroup Ogre + * A set of classes to interact with Ogre's material system + * @{ + */ + +#include "../../Main/Platform.hpp" + +#include +#include + +namespace sh +{ + class OgreMaterialSerializer; + + class OgrePlatform : public Platform, public Ogre::MaterialManager::Listener + { + public: + OgrePlatform (const std::string& resourceGroupName, const std::string& basePath); + virtual ~OgrePlatform (); + + virtual Ogre::Technique* handleSchemeNotFound ( + unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, + unsigned short lodIndex, const Ogre::Renderable *rend); + + static OgreMaterialSerializer& getSerializer(); + + private: + virtual bool isProfileSupported (const std::string& profile); + + virtual void serializeShaders (const std::string& file); + virtual void deserializeShaders (const std::string& file); + + virtual boost::shared_ptr createMaterial (const std::string& name); + + virtual boost::shared_ptr createGpuProgram ( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, Language lang); + + virtual void setSharedParameter (const std::string& name, PropertyValuePtr value); + + friend class ShaderInstance; + friend class Factory; + + protected: + virtual bool supportsShaderSerialization (); + virtual bool supportsMaterialQueuedListener (); + + std::string mResourceGroup; + + static OgreMaterialSerializer* sSerializer; + + std::map mSharedParameters; + }; +} + +/** + * @} + * @} + */ + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp new file mode 100644 index 0000000000..0938cf667d --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp @@ -0,0 +1,40 @@ +#include "OgreTextureUnitState.hpp" + +#include "OgrePass.hpp" +#include "OgrePlatform.hpp" +#include "OgreMaterialSerializer.hpp" + +namespace sh +{ + OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent) + : TextureUnitState() + { + mTextureUnitState = parent->getOgrePass()->createTextureUnitState(""); + } + + bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) + { + OgreMaterialSerializer& s = OgrePlatform::getSerializer(); + + if (name == "texture_alias") + { + // texture alias in this library refers to something else than in ogre + // delegate up + return TextureUnitState::setPropertyOverride (name, value, context); + } + else if (name == "direct_texture") + { + setTextureName (retrieveValue(value, context).get()); + return true; + } + else if (name == "create_in_ffp") + return true; // handled elsewhere + + return s.setTextureUnitProperty (name, retrieveValue(value, context).get(), mTextureUnitState); + } + + void OgreTextureUnitState::setTextureName (const std::string& textureName) + { + mTextureUnitState->setTextureName(textureName); + } +} diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp new file mode 100644 index 0000000000..d36f4b945a --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp @@ -0,0 +1,27 @@ +#ifndef SH_OGRETEXTUREUNITSTATE_H +#define SH_OGRETEXTUREUNITSTATE_H + +#include + +#include "../../Main/Platform.hpp" + +namespace sh +{ + class OgrePass; + + class OgreTextureUnitState : public TextureUnitState + { + public: + OgreTextureUnitState (OgrePass* parent); + + virtual void setTextureName (const std::string& textureName); + + private: + Ogre::TextureUnitState* mTextureUnitState; + + protected: + virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context); + }; +} + +#endif diff --git a/extern/shiny/Preprocessor/aq.cpp b/extern/shiny/Preprocessor/aq.cpp new file mode 100644 index 0000000000..b81d5b3324 --- /dev/null +++ b/extern/shiny/Preprocessor/aq.cpp @@ -0,0 +1,236 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001 Daniel C. Nuffer. + Copyright (c) 2001-2011 Hartmut Kaiser. + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include + +#include +#include + +#include // configuration data +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +int aq_grow(aq_queue q) +{ + using namespace std; // some systems have memcpy/realloc in std + std::size_t new_size = q->max_size << 1; + aq_stdelement* new_queue = (aq_stdelement*)realloc(q->queue, + new_size * sizeof(aq_stdelement)); + + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->max_size < 100000); + BOOST_ASSERT(q->size <= q->max_size); + +#define ASSERT_SIZE BOOST_ASSERT( \ + ((q->tail + q->max_size + 1) - q->head) % q->max_size == \ + q->size % q->max_size) + + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + if (!new_queue) + { + BOOST_ASSERT(0); + return 0; + } + + q->queue = new_queue; + if (q->tail <= q->head) /* tail has wrapped around */ + { + /* move the tail from the beginning to the end */ + memcpy(q->queue + q->max_size, q->queue, + (q->tail + 1) * sizeof(aq_stdelement)); + q->tail += q->max_size; + } + q->max_size = new_size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_enqueue(aq_queue q, aq_stdelement e) +{ + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_FULL(q)) + if (!aq_grow(q)) + return 0; + + ++q->tail; + if (q->tail == q->max_size) + q->tail = 0; + + q->queue[q->tail] = e; + ++q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_enqueue_front(aq_queue q, aq_stdelement e) +{ + BOOST_ASSERT(NULL != q); + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_FULL(q)) + if (!aq_grow(q)) + return 0; + + if (q->head == 0) + q->head = q->max_size - 1; + else + --q->head; + + q->queue[q->head] = e; + ++q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_serve(aq_queue q, aq_stdelement *e) +{ + + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_EMPTY(q)) + return 0; + + *e = q->queue[q->head]; + return aq_pop(q); +} + +int aq_pop(aq_queue q) +{ + + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_EMPTY(q)) + return 0; + + ++q->head; + if (q->head == q->max_size) + q->head = 0; + --q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +aq_queue aq_create(void) +{ + aq_queue q; + + using namespace std; // some systems have malloc in std + q = (aq_queue)malloc(sizeof(aq_queuetype)); + if (!q) + { + return 0; + } + + q->max_size = 8; /* initial size */ + q->queue = (aq_stdelement*)malloc( + sizeof(aq_stdelement) * q->max_size); + if (!q->queue) + { + free(q); + return 0; + } + + q->head = 0; + q->tail = q->max_size - 1; + q->size = 0; + + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return q; +} + +void aq_terminate(aq_queue q) +{ + using namespace std; // some systems have free in std + + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + free(q->queue); + free(q); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + diff --git a/extern/shiny/Preprocessor/cpp_re.cpp b/extern/shiny/Preprocessor/cpp_re.cpp new file mode 100644 index 0000000000..69d77c3726 --- /dev/null +++ b/extern/shiny/Preprocessor/cpp_re.cpp @@ -0,0 +1,442 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Copyright (c) 2001 Daniel C. Nuffer + Copyright (c) 2001-2011 Hartmut Kaiser. + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + TODO: + It also may be necessary to add $ to identifiers, for asm. + handle errors better. + have some easier way to parse strings instead of files (done) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include + +#include +#include +#include +#include +#include +#include +#include + +#include // configuration data + +#if defined(BOOST_HAS_UNISTD_H) +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if defined(BOOST_MSVC) +#pragma warning (disable: 4101) // 'foo' : unreferenced local variable +#pragma warning (disable: 4102) // 'foo' : unreferenced label +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_BSIZE 196608 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT limit +#define YYMARKER marker +#define YYFILL(n) \ + { \ + cursor = uchar_wrapper(fill(s, cursor), cursor.column); \ + limit = uchar_wrapper (s->lim); \ + } \ + /**/ + +#include + +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_UPDATE_CURSOR() \ + { \ + s->line += count_backslash_newlines(s, cursor); \ + s->curr_column = cursor.column; \ + s->cur = cursor; \ + s->lim = limit; \ + s->ptr = marker; \ + } \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_RET(i) \ + { \ + BOOST_WAVE_UPDATE_CURSOR() \ + if (s->cur > s->lim) \ + return T_EOF; /* may happen for empty files */ \ + return (i); \ + } \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +#define RE2C_ASSERT BOOST_ASSERT + +int get_one_char(Scanner *s) +{ + if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + if (s->act < s->last) + return *(s->act)++; + } + return -1; +} + +std::ptrdiff_t rewind_stream (Scanner *s, int cnt) +{ + if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + s->act += cnt; + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + return s->act - s->first; + } + return 0; +} + +std::size_t get_first_eol_offset(Scanner* s) +{ + if (!AQ_EMPTY(s->eol_offsets)) + { + return s->eol_offsets->queue[s->eol_offsets->head]; + } + else + { + return (unsigned int)-1; + } +} + +void adjust_eol_offsets(Scanner* s, std::size_t adjustment) +{ + aq_queue q; + std::size_t i; + + if (!s->eol_offsets) + s->eol_offsets = aq_create(); + + q = s->eol_offsets; + + if (AQ_EMPTY(q)) + return; + + i = q->head; + while (i != q->tail) + { + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; + ++i; + if (i == q->max_size) + i = 0; + } + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; +} + +int count_backslash_newlines(Scanner *s, uchar *cursor) +{ + std::size_t diff, offset; + int skipped = 0; + + /* figure out how many backslash-newlines skipped over unknowingly. */ + diff = cursor - s->bot; + offset = get_first_eol_offset(s); + while (offset <= diff && offset != (unsigned int)-1) + { + skipped++; + aq_pop(s->eol_offsets); + offset = get_first_eol_offset(s); + } + return skipped; +} + +bool is_backslash(uchar *p, uchar *end, int &len) +{ + if (*p == '\\') { + len = 1; + return true; + } + else if (*p == '?' && *(p+1) == '?' && (p+2 < end && *(p+2) == '/')) { + len = 3; + return true; + } + return false; +} + +uchar *fill(Scanner *s, uchar *cursor) +{ + using namespace std; // some systems have memcpy etc. in namespace std + if(!s->eof) + { + uchar* p; + std::ptrdiff_t cnt = s->tok - s->bot; + if(cnt) + { + if (NULL == s->lim) + s->lim = s->top; + memmove(s->bot, s->tok, s->lim - s->tok); + s->tok = s->cur = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->lim -= cnt; + adjust_eol_offsets(s, cnt); + } + + if((s->top - s->lim) < BOOST_WAVE_BSIZE) + { + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BOOST_WAVE_BSIZE)*sizeof(uchar)); + if (buf == 0) + { + using namespace std; // some systems have printf in std + if (0 != s->error_proc) { + (*s->error_proc)(s, lexing_exception::unexpected_error, + "Out of memory!"); + } + else + printf("Out of memory!\n"); + + /* get the scanner to stop */ + *cursor = 0; + return cursor; + } + + memmove(buf, s->tok, s->lim - s->tok); + s->tok = s->cur = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BOOST_WAVE_BSIZE]; + free(s->bot); + s->bot = buf; + } + + if (s->act != 0) { + cnt = s->last - s->act; + if (cnt > BOOST_WAVE_BSIZE) + cnt = BOOST_WAVE_BSIZE; + memmove(s->lim, s->act, cnt); + s->act += cnt; + if (cnt != BOOST_WAVE_BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + + /* backslash-newline erasing time */ + + /* first scan for backslash-newline and erase them */ + for (p = s->lim; p < s->lim + cnt - 2; ++p) + { + int len = 0; + if (is_backslash(p, s->lim + cnt, len)) + { + if (*(p+len) == '\n') + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + else if (*(p+len) == '\r') + { + if (*(p+len+1) == '\n') + { + int offset = len + 2; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + else + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + } + } + + /* FIXME: the following code should be fixed to recognize correctly the + trigraph backslash token */ + + /* check to see if what we just read ends in a backslash */ + if (cnt >= 2) + { + uchar last = s->lim[cnt-1]; + uchar last2 = s->lim[cnt-2]; + /* check \ EOB */ + if (last == '\\') + { + int next = get_one_char(s); + /* check for \ \n or \ \r or \ \r \n straddling the border */ + if (next == '\n') + { + --cnt; /* chop the final \, we've already read the \n. */ + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + else if (next == '\r') + { + int next2 = get_one_char(s); + if (next2 == '\n') + { + --cnt; /* skip the backslash */ + } + else + { + /* rewind one, and skip one char */ + rewind_stream(s, -1); + --cnt; + } + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + else if (next != -1) /* -1 means end of file */ + { + /* next was something else, so rewind the stream */ + rewind_stream(s, -1); + } + } + /* check \ \r EOB */ + else if (last == '\r' && last2 == '\\') + { + int next = get_one_char(s); + if (next == '\n') + { + cnt -= 2; /* skip the \ \r */ + } + else + { + /* rewind one, and skip two chars */ + rewind_stream(s, -1); + cnt -= 2; + } + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + /* check \ \n EOB */ + else if (last == '\n' && last2 == '\\') + { + cnt -= 2; + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + } + + s->lim += cnt; + if (s->eof) /* eof needs adjusting if we erased backslash-newlines */ + { + s->eof = s->lim; + *(s->eof)++ = '\0'; + } + } + return cursor; +} + +/////////////////////////////////////////////////////////////////////////////// +// Special wrapper class holding the current cursor position +struct uchar_wrapper +{ + uchar_wrapper (uchar *base_cursor, unsigned int column = 1) + : base_cursor(base_cursor), column(column) + {} + + uchar_wrapper& operator++() + { + ++base_cursor; + ++column; + return *this; + } + + uchar_wrapper& operator--() + { + --base_cursor; + --column; + return *this; + } + + uchar operator* () const + { + return *base_cursor; + } + + operator uchar *() const + { + return base_cursor; + } + + friend std::ptrdiff_t + operator- (uchar_wrapper const& lhs, uchar_wrapper const& rhs) + { + return lhs.base_cursor - rhs.base_cursor; + } + + uchar *base_cursor; + unsigned int column; +}; + +/////////////////////////////////////////////////////////////////////////////// +boost::wave::token_id scan(Scanner *s) +{ + BOOST_ASSERT(0 != s->error_proc); // error handler must be given + + uchar_wrapper cursor (s->tok = s->cur, s->column = s->curr_column); + uchar_wrapper marker (s->ptr); + uchar_wrapper limit (s->lim); + +// include the correct Re2C token definition rules +#if BOOST_WAVE_USE_STRICT_LEXER != 0 +#include "strict_cpp_re.inc" +#else +#include "cpp_re.inc" +#endif + +} /* end of scan */ + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#undef BOOST_WAVE_RET +#undef BOOST_WAVE_BSIZE +#undef YYCTYPE +#undef YYCURSOR +#undef YYLIMIT +#undef YYMARKER +#undef YYFILL + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + diff --git a/extern/shiny/Preprocessor/cpp_re.inc b/extern/shiny/Preprocessor/cpp_re.inc new file mode 100644 index 0000000000..afb7fc189e --- /dev/null +++ b/extern/shiny/Preprocessor/cpp_re.inc @@ -0,0 +1,9044 @@ +/* Generated by re2c 0.13.5 on Sun Jan 09 15:38:23 2011 */ +#line 1 "cpp.re" +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Copyright (c) 2001 Daniel C. Nuffer + Copyright (c) 2001-2011 Hartmut Kaiser. + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + This is a lexer conforming to the Standard with a few exceptions. + So it does allow the '$' to be part of identifiers. If you need strict + Standards conforming behaviour, please include the lexer definition + provided in the file strict_cpp.re. + + TODO: + handle errors better. +=============================================================================*/ + +#line 40 "cpp.re" + + + +#line 25 "cpp_re.inc" +{ + YYCTYPE yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + /* table 1 .. 8: 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 60, 32, 60, 60, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 60, 60, 52, 60, 60, 60, 60, 56, + 60, 60, 156, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 44, 57, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 58, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + /* table 9 .. 12: 256 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 80, 0, 80, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 64, 0, 64, 96, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 64, 64, 64, 64, 64, 0, + 64, 224, 224, 224, 224, 224, 224, 96, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 64, 0, 64, 64, 96, + 64, 224, 224, 224, 224, 224, 224, 96, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + }; + + if ((YYLIMIT - YYCURSOR) < 17) YYFILL(17); + yych = *YYCURSOR; + switch (yych) { + case 0x00: goto yy90; + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: goto yy93; + case '\t': + case '\v': + case '\f': goto yy84; + case '\n': goto yy87; + case '\r': goto yy89; + case ' ': goto yy86; + case '!': goto yy68; + case '"': goto yy79; + case '#': goto yy45; + case '$': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'S': + case 'T': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case 'h': + case 'j': + case 'k': + case 'q': + case 'y': + case 'z': goto yy82; + case '%': goto yy37; + case '&': goto yy62; + case '\'': goto yy77; + case '(': goto yy47; + case ')': goto yy49; + case '*': goto yy57; + case '+': goto yy53; + case ',': goto yy74; + case '-': goto yy55; + case '.': goto yy4; + case '/': goto yy2; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy6; + case ':': goto yy43; + case ';': goto yy51; + case '<': goto yy33; + case '=': goto yy70; + case '>': goto yy72; + case '?': goto yy31; + case 'L': goto yy76; + case 'R': goto yy80; + case 'U': goto yy81; + case '[': goto yy39; + case '\\': goto yy83; + case ']': goto yy41; + case '^': goto yy59; + case '_': goto yy28; + case 'a': goto yy8; + case 'b': goto yy10; + case 'c': goto yy11; + case 'd': goto yy12; + case 'e': goto yy13; + case 'f': goto yy14; + case 'g': goto yy15; + case 'i': goto yy16; + case 'l': goto yy17; + case 'm': goto yy18; + case 'n': goto yy19; + case 'o': goto yy20; + case 'p': goto yy21; + case 'r': goto yy22; + case 's': goto yy23; + case 't': goto yy24; + case 'u': goto yy25; + case 'v': goto yy26; + case 'w': goto yy27; + case 'x': goto yy61; + case '{': goto yy29; + case '|': goto yy64; + case '}': goto yy35; + case '~': goto yy66; + default: goto yy92; + } +yy2: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '.') { + if (yych == '*') goto yy998; + } else { + if (yych <= '/') goto yy996; + if (yych == '=') goto yy994; + } +#line 188 "cpp.re" + { BOOST_WAVE_RET(T_DIVIDE); } +#line 238 "cpp_re.inc" +yy4: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '-') { + if (yych == '*') goto yy988; + } else { + if (yych <= '.') goto yy990; + if (yych <= '/') goto yy5; + if (yych <= '9') goto yy991; + } +yy5: +#line 174 "cpp.re" + { BOOST_WAVE_RET(T_DOT); } +#line 252 "cpp_re.inc" +yy6: + ++YYCURSOR; +yy7: +#line 45 "cpp.re" + { goto pp_number; } +#line 258 "cpp_re.inc" +yy8: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'l': goto yy964; + case 'n': goto yy965; + case 's': goto yy966; + case 'u': goto yy967; + default: goto yy109; + } +yy9: +#line 290 "cpp.re" + { BOOST_WAVE_RET(T_IDENTIFIER); } +#line 272 "cpp_re.inc" +yy10: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'n') { + if (yych == 'i') goto yy946; + goto yy109; + } else { + if (yych <= 'o') goto yy947; + if (yych == 'r') goto yy948; + goto yy109; + } +yy11: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'a': goto yy893; + case 'h': goto yy894; + case 'l': goto yy895; + case 'o': goto yy896; + default: goto yy109; + } +yy12: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'n') { + if (yych == 'e') goto yy855; + goto yy109; + } else { + if (yych <= 'o') goto yy856; + if (yych == 'y') goto yy858; + goto yy109; + } +yy13: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'm') { + if (yych == 'l') goto yy830; + goto yy109; + } else { + if (yych <= 'n') goto yy831; + if (yych == 'x') goto yy832; + goto yy109; + } +yy14: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'a': goto yy811; + case 'l': goto yy812; + case 'o': goto yy813; + case 'r': goto yy814; + default: goto yy109; + } +yy15: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy807; + goto yy109; +yy16: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'l') { + if (yych == 'f') goto yy791; + goto yy109; + } else { + if (yych <= 'm') goto yy793; + if (yych <= 'n') goto yy794; + goto yy109; + } +yy17: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy787; + goto yy109; +yy18: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy780; + goto yy109; +yy19: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'e') { + if (yych == 'a') goto yy747; + if (yych <= 'd') goto yy109; + goto yy748; + } else { + if (yych <= 'o') { + if (yych <= 'n') goto yy109; + goto yy749; + } else { + if (yych == 'u') goto yy750; + goto yy109; + } + } +yy20: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'p') goto yy733; + if (yych == 'r') goto yy734; + goto yy109; +yy21: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy712; + if (yych == 'u') goto yy713; + goto yy109; +yy22: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy684; + goto yy109; +yy23: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 's') { + if (yych <= 'g') goto yy109; + if (yych <= 'h') goto yy638; + if (yych <= 'i') goto yy639; + goto yy109; + } else { + if (yych <= 't') goto yy640; + if (yych == 'w') goto yy641; + goto yy109; + } +yy24: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'h') { + if (yych == 'e') goto yy591; + if (yych <= 'g') goto yy109; + goto yy592; + } else { + if (yych <= 'r') { + if (yych <= 'q') goto yy109; + goto yy593; + } else { + if (yych == 'y') goto yy594; + goto yy109; + } + } +yy25: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '8') { + if (yych <= '&') { + if (yych == '"') goto yy129; + goto yy109; + } else { + if (yych <= '\'') goto yy131; + if (yych <= '7') goto yy109; + goto yy573; + } + } else { + if (yych <= 'm') { + if (yych == 'R') goto yy128; + goto yy109; + } else { + if (yych <= 'n') goto yy574; + if (yych == 's') goto yy575; + goto yy109; + } + } +yy26: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy555; + if (yych == 'o') goto yy556; + goto yy109; +yy27: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'c') goto yy543; + if (yych == 'h') goto yy544; + goto yy109; +yy28: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case '_': goto yy454; + case 'a': goto yy455; + case 'b': goto yy456; + case 'c': goto yy457; + case 'd': goto yy458; + case 'f': goto yy459; + case 'i': goto yy460; + case 's': goto yy461; + default: goto yy109; + } +yy29: + ++YYCURSOR; +#line 138 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACE); } +#line 466 "cpp_re.inc" +yy31: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '?') goto yy419; +yy32: +#line 163 "cpp.re" + { BOOST_WAVE_RET(T_QUESTION_MARK); } +#line 474 "cpp_re.inc" +yy33: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= ':') { + if (yych == '%') goto yy415; + if (yych >= ':') goto yy413; + } else { + if (yych <= ';') goto yy34; + if (yych <= '<') goto yy411; + if (yych <= '=') goto yy409; + } +yy34: +#line 204 "cpp.re" + { BOOST_WAVE_RET(T_LESS); } +#line 488 "cpp_re.inc" +yy35: + ++YYCURSOR; +#line 141 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACE); } +#line 493 "cpp_re.inc" +yy37: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '<') { + if (yych == ':') goto yy400; + } else { + if (yych <= '=') goto yy402; + if (yych <= '>') goto yy404; + } +#line 189 "cpp.re" + { BOOST_WAVE_RET(T_PERCENT); } +#line 504 "cpp_re.inc" +yy39: + ++YYCURSOR; +#line 144 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACKET); } +#line 509 "cpp_re.inc" +yy41: + ++YYCURSOR; +#line 147 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACKET); } +#line 514 "cpp_re.inc" +yy43: + ++YYCURSOR; + if ((yych = *YYCURSOR) == ':') goto yy396; + if (yych == '>') goto yy398; +#line 161 "cpp.re" + { BOOST_WAVE_RET(T_COLON); } +#line 521 "cpp_re.inc" +yy45: + yyaccept = 3; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'c') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy273; + } else { + if (yych <= '\f') goto yy273; + if (yych >= ' ') goto yy273; + } + } else { + if (yych <= '.') { + if (yych == '#') goto yy284; + } else { + if (yych <= '/') goto yy273; + if (yych == '?') goto yy283; + } + } + } else { + if (yych <= 'p') { + if (yych <= 'i') { + if (yych <= 'e') goto yy273; + if (yych >= 'i') goto yy273; + } else { + if (yych == 'l') goto yy273; + if (yych >= 'p') goto yy273; + } + } else { + if (yych <= 't') { + if (yych == 'r') goto yy273; + } else { + if (yych == 'v') goto yy46; + if (yych <= 'w') goto yy273; + } + } + } +yy46: +#line 150 "cpp.re" + { BOOST_WAVE_RET(T_POUND); } +#line 562 "cpp_re.inc" +yy47: + ++YYCURSOR; +#line 158 "cpp.re" + { BOOST_WAVE_RET(T_LEFTPAREN); } +#line 567 "cpp_re.inc" +yy49: + ++YYCURSOR; +#line 159 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTPAREN); } +#line 572 "cpp_re.inc" +yy51: + ++YYCURSOR; +#line 160 "cpp.re" + { BOOST_WAVE_RET(T_SEMICOLON); } +#line 577 "cpp_re.inc" +yy53: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '+') goto yy268; + if (yych == '=') goto yy270; +#line 185 "cpp.re" + { BOOST_WAVE_RET(T_PLUS); } +#line 584 "cpp_re.inc" +yy55: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '<') { + if (yych == '-') goto yy262; + } else { + if (yych <= '=') goto yy264; + if (yych <= '>') goto yy260; + } +#line 186 "cpp.re" + { BOOST_WAVE_RET(T_MINUS); } +#line 595 "cpp_re.inc" +yy57: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy258; +#line 187 "cpp.re" + { BOOST_WAVE_RET(T_STAR); } +#line 601 "cpp_re.inc" +yy59: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy256; +#line 190 "cpp.re" + { BOOST_WAVE_RET(T_XOR); } +#line 607 "cpp_re.inc" +yy61: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy249; + goto yy109; +yy62: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '&') goto yy245; + if (yych == '=') goto yy247; +#line 193 "cpp.re" + { BOOST_WAVE_RET(T_AND); } +#line 619 "cpp_re.inc" +yy64: + yyaccept = 4; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '>') { + if (yych == '=') goto yy240; + } else { + if (yych <= '?') goto yy237; + if (yych == '|') goto yy238; + } +yy65: +#line 195 "cpp.re" + { BOOST_WAVE_RET(T_OR); } +#line 632 "cpp_re.inc" +yy66: + ++YYCURSOR; +#line 198 "cpp.re" + { BOOST_WAVE_RET(T_COMPL); } +#line 637 "cpp_re.inc" +yy68: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy235; +#line 201 "cpp.re" + { BOOST_WAVE_RET(T_NOT); } +#line 643 "cpp_re.inc" +yy70: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy233; +#line 203 "cpp.re" + { BOOST_WAVE_RET(T_ASSIGN); } +#line 649 "cpp_re.inc" +yy72: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '<') goto yy73; + if (yych <= '=') goto yy227; + if (yych <= '>') goto yy229; +yy73: +#line 205 "cpp.re" + { BOOST_WAVE_RET(T_GREATER); } +#line 658 "cpp_re.inc" +yy74: + ++YYCURSOR; +#line 237 "cpp.re" + { BOOST_WAVE_RET(T_COMMA); } +#line 663 "cpp_re.inc" +yy76: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '?') { + if (yych <= '&') { + if (yych <= '"') { + if (yych <= '!') goto yy9; + goto yy137; + } else { + if (yych == '$') goto yy108; + goto yy9; + } + } else { + if (yych <= '/') { + if (yych <= '\'') goto yy226; + goto yy9; + } else { + if (yych <= '9') goto yy108; + if (yych <= '>') goto yy9; + goto yy111; + } + } + } else { + if (yych <= '[') { + if (yych <= 'Q') { + if (yych <= '@') goto yy9; + goto yy108; + } else { + if (yych <= 'R') goto yy225; + if (yych <= 'Z') goto yy108; + goto yy9; + } + } else { + if (yych <= '_') { + if (yych <= '\\') goto yy110; + if (yych <= '^') goto yy9; + goto yy108; + } else { + if (yych <= '`') goto yy9; + if (yych <= 'z') goto yy108; + goto yy9; + } + } + } +yy77: + yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\f') { + if (yych == '\t') goto yy182; + if (yych >= '\v') goto yy182; + } else { + if (yych <= 0x1F) goto yy78; + if (yych != '\'') goto yy182; + } +yy78: +#line 339 "cpp.re" + { BOOST_WAVE_RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); } +#line 721 "cpp_re.inc" +yy79: + yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\n') { + if (yych == '\t') goto yy138; + goto yy78; + } else { + if (yych <= '\f') goto yy138; + if (yych <= 0x1F) goto yy78; + goto yy138; + } +yy80: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '"') goto yy135; + goto yy109; +yy81: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '&') { + if (yych == '"') goto yy129; + goto yy109; + } else { + if (yych <= '\'') goto yy131; + if (yych == 'R') goto yy128; + goto yy109; + } +yy82: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + goto yy109; +yy83: + yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'U') goto yy100; + if (yych == 'u') goto yy98; + goto yy78; +yy84: + ++YYCURSOR; + yych = *YYCURSOR; + goto yy97; +yy85: +#line 319 "cpp.re" + { BOOST_WAVE_RET(T_SPACE); } +#line 766 "cpp_re.inc" +yy86: + yych = *++YYCURSOR; + goto yy97; +yy87: + ++YYCURSOR; +yy88: +#line 322 "cpp.re" + { + s->line++; + cursor.column = 1; + BOOST_WAVE_RET(T_NEWLINE); + } +#line 779 "cpp_re.inc" +yy89: + yych = *++YYCURSOR; + if (yych == '\n') goto yy95; + goto yy88; +yy90: + ++YYCURSOR; +#line 329 "cpp.re" + { + if (s->eof && cursor != s->eof) + { + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\000' in input stream"); + } + BOOST_WAVE_RET(T_EOF); + } +#line 796 "cpp_re.inc" +yy92: + yych = *++YYCURSOR; + goto yy78; +yy93: + ++YYCURSOR; +#line 342 "cpp.re" + { + // flag the error + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\%03o' in input stream", *--YYCURSOR); + } +#line 809 "cpp_re.inc" +yy95: + yych = *++YYCURSOR; + goto yy88; +yy96: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy97: + if (yybm[256+yych] & 16) { + goto yy96; + } + goto yy85; +yy98: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy125; + } else { + if (yych <= 'F') goto yy125; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy125; + } +yy99: + YYCURSOR = YYMARKER; + if (yyaccept <= 56) { + if (yyaccept <= 28) { + if (yyaccept <= 14) { + if (yyaccept <= 7) { + if (yyaccept <= 3) { + if (yyaccept <= 1) { + if (yyaccept <= 0) { + goto yy5; + } else { + goto yy9; + } + } else { + if (yyaccept <= 2) { + goto yy32; + } else { + goto yy46; + } + } + } else { + if (yyaccept <= 5) { + if (yyaccept <= 4) { + goto yy65; + } else { + goto yy78; + } + } else { + if (yyaccept <= 6) { + goto yy142; + } else { + goto yy192; + } + } + } + } else { + if (yyaccept <= 11) { + if (yyaccept <= 9) { + if (yyaccept <= 8) { + goto yy251; + } else { + goto yy255; + } + } else { + if (yyaccept <= 10) { + goto yy291; + } else { + goto yy306; + } + } + } else { + if (yyaccept <= 13) { + if (yyaccept <= 12) { + goto yy401; + } else { + goto yy429; + } + } else { + goto yy433; + } + } + } + } else { + if (yyaccept <= 21) { + if (yyaccept <= 18) { + if (yyaccept <= 16) { + if (yyaccept <= 15) { + goto yy437; + } else { + goto yy468; + } + } else { + if (yyaccept <= 17) { + goto yy474; + } else { + goto yy482; + } + } + } else { + if (yyaccept <= 20) { + if (yyaccept <= 19) { + goto yy490; + } else { + goto yy495; + } + } else { + goto yy500; + } + } + } else { + if (yyaccept <= 25) { + if (yyaccept <= 23) { + if (yyaccept <= 22) { + goto yy503; + } else { + goto yy513; + } + } else { + if (yyaccept <= 24) { + goto yy519; + } else { + goto yy522; + } + } + } else { + if (yyaccept <= 27) { + if (yyaccept <= 26) { + goto yy529; + } else { + goto yy536; + } + } else { + goto yy538; + } + } + } + } + } else { + if (yyaccept <= 42) { + if (yyaccept <= 35) { + if (yyaccept <= 32) { + if (yyaccept <= 30) { + if (yyaccept <= 29) { + goto yy540; + } else { + goto yy542; + } + } else { + if (yyaccept <= 31) { + goto yy548; + } else { + goto yy554; + } + } + } else { + if (yyaccept <= 34) { + if (yyaccept <= 33) { + goto yy564; + } else { + goto yy566; + } + } else { + goto yy572; + } + } + } else { + if (yyaccept <= 39) { + if (yyaccept <= 37) { + if (yyaccept <= 36) { + goto yy579; + } else { + goto yy587; + } + } else { + if (yyaccept <= 38) { + goto yy590; + } else { + goto yy603; + } + } + } else { + if (yyaccept <= 41) { + if (yyaccept <= 40) { + goto yy605; + } else { + goto yy608; + } + } else { + goto yy611; + } + } + } + } else { + if (yyaccept <= 49) { + if (yyaccept <= 46) { + if (yyaccept <= 44) { + if (yyaccept <= 43) { + goto yy613; + } else { + goto yy619; + } + } else { + if (yyaccept <= 45) { + goto yy628; + } else { + goto yy630; + } + } + } else { + if (yyaccept <= 48) { + if (yyaccept <= 47) { + goto yy637; + } else { + goto yy646; + } + } else { + goto yy652; + } + } + } else { + if (yyaccept <= 53) { + if (yyaccept <= 51) { + if (yyaccept <= 50) { + goto yy656; + } else { + goto yy663; + } + } else { + if (yyaccept <= 52) { + goto yy669; + } else { + goto yy675; + } + } + } else { + if (yyaccept <= 55) { + if (yyaccept <= 54) { + goto yy679; + } else { + goto yy683; + } + } else { + goto yy691; + } + } + } + } + } + } else { + if (yyaccept <= 85) { + if (yyaccept <= 71) { + if (yyaccept <= 64) { + if (yyaccept <= 60) { + if (yyaccept <= 58) { + if (yyaccept <= 57) { + goto yy705; + } else { + goto yy711; + } + } else { + if (yyaccept <= 59) { + goto yy718; + } else { + goto yy727; + } + } + } else { + if (yyaccept <= 62) { + if (yyaccept <= 61) { + goto yy732; + } else { + goto yy735; + } + } else { + if (yyaccept <= 63) { + goto yy739; + } else { + goto yy746; + } + } + } + } else { + if (yyaccept <= 68) { + if (yyaccept <= 66) { + if (yyaccept <= 65) { + goto yy756; + } else { + goto yy759; + } + } else { + if (yyaccept <= 67) { + goto yy763; + } else { + goto yy769; + } + } + } else { + if (yyaccept <= 70) { + if (yyaccept <= 69) { + goto yy771; + } else { + goto yy779; + } + } else { + goto yy786; + } + } + } + } else { + if (yyaccept <= 78) { + if (yyaccept <= 75) { + if (yyaccept <= 73) { + if (yyaccept <= 72) { + goto yy790; + } else { + goto yy792; + } + } else { + if (yyaccept <= 74) { + goto yy797; + } else { + goto yy801; + } + } + } else { + if (yyaccept <= 77) { + if (yyaccept <= 76) { + goto yy806; + } else { + goto yy810; + } + } else { + goto yy819; + } + } + } else { + if (yyaccept <= 82) { + if (yyaccept <= 80) { + if (yyaccept <= 79) { + goto yy821; + } else { + goto yy825; + } + } else { + if (yyaccept <= 81) { + goto yy829; + } else { + goto yy838; + } + } + } else { + if (yyaccept <= 84) { + if (yyaccept <= 83) { + goto yy843; + } else { + goto yy848; + } + } else { + goto yy851; + } + } + } + } + } else { + if (yyaccept <= 99) { + if (yyaccept <= 92) { + if (yyaccept <= 89) { + if (yyaccept <= 87) { + if (yyaccept <= 86) { + goto yy854; + } else { + goto yy857; + } + } else { + if (yyaccept <= 88) { + goto yy869; + } else { + goto yy874; + } + } + } else { + if (yyaccept <= 91) { + if (yyaccept <= 90) { + goto yy881; + } else { + goto yy886; + } + } else { + goto yy892; + } + } + } else { + if (yyaccept <= 96) { + if (yyaccept <= 94) { + if (yyaccept <= 93) { + goto yy901; + } else { + goto yy908; + } + } else { + if (yyaccept <= 95) { + goto yy910; + } else { + goto yy916; + } + } + } else { + if (yyaccept <= 98) { + if (yyaccept <= 97) { + goto yy921; + } else { + goto yy925; + } + } else { + goto yy928; + } + } + } + } else { + if (yyaccept <= 106) { + if (yyaccept <= 103) { + if (yyaccept <= 101) { + if (yyaccept <= 100) { + goto yy934; + } else { + goto yy938; + } + } else { + if (yyaccept <= 102) { + goto yy943; + } else { + goto yy945; + } + } + } else { + if (yyaccept <= 105) { + if (yyaccept <= 104) { + goto yy952; + } else { + goto yy955; + } + } else { + goto yy960; + } + } + } else { + if (yyaccept <= 110) { + if (yyaccept <= 108) { + if (yyaccept <= 107) { + goto yy963; + } else { + goto yy970; + } + } else { + if (yyaccept <= 109) { + goto yy972; + } else { + goto yy974; + } + } + } else { + if (yyaccept <= 112) { + if (yyaccept <= 111) { + goto yy978; + } else { + goto yy985; + } + } else { + goto yy987; + } + } + } + } + } + } +yy100: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy101; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy101: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy102; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy102: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy103; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy103: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy104; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy104: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy105; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy105: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy106; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy106: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy107; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy107: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy108; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy108: + yyaccept = 1; + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy109: + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych != '\\') goto yy9; +yy110: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == 'U') goto yy114; + if (yych == 'u') goto yy113; + goto yy99; +yy111: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych != '?') goto yy99; + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == '/') goto yy110; + goto yy99; +yy113: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy122; + goto yy99; + } else { + if (yych <= 'F') goto yy122; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy122; + goto yy99; + } +yy114: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy115; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy115: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy116; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy116: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy117; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy117: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy118; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy118: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy119; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy119: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy120; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy120: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy121; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy121: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy108; + goto yy99; + } else { + if (yych <= 'F') goto yy108; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy108; + goto yy99; + } +yy122: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy123; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy123: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy124; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy124: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy108; + goto yy99; + } else { + if (yych <= 'F') goto yy108; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy108; + goto yy99; + } +yy125: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy126; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy126: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy127; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy127: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy108; + goto yy99; + } else { + if (yych <= 'F') goto yy108; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy108; + goto yy99; + } +yy128: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '"') goto yy133; + goto yy109; +yy129: + ++YYCURSOR; +#line 274 "cpp.re" + { + if (s->act_in_cpp0x_mode) + goto extstringlit; + --YYCURSOR; + BOOST_WAVE_RET(T_IDENTIFIER); + } +#line 1591 "cpp_re.inc" +yy131: + ++YYCURSOR; +#line 266 "cpp.re" + { + if (s->act_in_cpp0x_mode) + goto extcharlit; + --YYCURSOR; + BOOST_WAVE_RET(T_IDENTIFIER); + } +#line 1601 "cpp_re.inc" +yy133: + ++YYCURSOR; +#line 282 "cpp.re" + { + if (s->act_in_cpp0x_mode) + goto extrawstringlit; + --YYCURSOR; + BOOST_WAVE_RET(T_IDENTIFIER); + } +#line 1611 "cpp_re.inc" +yy135: + ++YYCURSOR; +#line 258 "cpp.re" + { + if (s->act_in_cpp0x_mode) + goto extrawstringlit; + --YYCURSOR; + BOOST_WAVE_RET(T_IDENTIFIER); + } +#line 1621 "cpp_re.inc" +yy137: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy138: + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych >= '\\') goto yy140; +yy139: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy152; +yy140: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy137; + goto yy99; + } else { + if (yych <= '\'') goto yy137; + if (yych <= '/') goto yy99; + goto yy147; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy145; + goto yy99; + } else { + if (yych <= 'U') goto yy144; + if (yych == '\\') goto yy137; + goto yy99; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy137; + if (yych <= 'e') goto yy99; + goto yy137; + } else { + if (yych == 'n') goto yy137; + if (yych <= 'q') goto yy99; + goto yy137; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy99; + if (yych <= 't') goto yy137; + goto yy143; + } else { + if (yych <= 'v') goto yy137; + if (yych == 'x') goto yy146; + goto yy99; + } + } + } +yy141: + ++YYCURSOR; +yy142: +#line 255 "cpp.re" + { BOOST_WAVE_RET(T_STRINGLIT); } +#line 1695 "cpp_re.inc" +yy143: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy178; + goto yy99; + } else { + if (yych <= 'F') goto yy178; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy178; + goto yy99; + } +yy144: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy171; + goto yy99; + } else { + if (yych <= 'F') goto yy171; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy171; + goto yy99; + } +yy145: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy151; + goto yy140; +yy146: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 128) { + goto yy149; + } + goto yy99; +yy147: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '"') { + if (yych <= '\n') { + if (yych == '\t') goto yy137; + goto yy99; + } else { + if (yych <= '\f') goto yy137; + if (yych <= 0x1F) goto yy99; + if (yych <= '!') goto yy137; + goto yy141; + } + } else { + if (yych <= '>') { + if (yych <= '/') goto yy137; + if (yych >= '8') goto yy137; + } else { + if (yych <= '?') goto yy139; + if (yych == '\\') goto yy140; + goto yy137; + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy139; + goto yy140; +yy149: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 128) { + goto yy149; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy137; + goto yy99; + } else { + if (yych <= '\f') goto yy137; + if (yych <= 0x1F) goto yy99; + goto yy137; + } + } else { + if (yych <= '?') { + if (yych <= '"') goto yy141; + if (yych <= '>') goto yy137; + goto yy139; + } else { + if (yych == '\\') goto yy140; + goto yy137; + } + } +yy151: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych >= '\\') goto yy140; +yy152: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 1) { + goto yy152; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy137; + goto yy99; + } else { + if (yych <= '\f') goto yy137; + if (yych <= 0x1F) goto yy99; + goto yy137; + } + } else { + if (yych <= '/') { + if (yych <= '"') goto yy141; + if (yych <= '.') goto yy137; + } else { + if (yych == '\\') goto yy140; + goto yy137; + } + } +yy154: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 2) { + goto yy154; + } + if (yych <= '7') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy158; + if (yych <= '/') goto yy137; + goto yy147; + } + } + } else { + if (yych <= 'U') { + if (yych == '?') goto yy159; + if (yych <= 'T') goto yy137; + goto yy157; + } else { + if (yych <= 'u') { + if (yych <= 't') goto yy137; + } else { + if (yych == 'x') goto yy149; + goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + goto yy168; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + goto yy168; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych <= 'f') goto yy168; + goto yy137; + } + } + } +yy157: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + goto yy161; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + goto yy161; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych <= 'f') goto yy161; + goto yy137; + } + } + } +yy158: + yyaccept = 6; + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy142; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy139; + goto yy140; +yy159: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych >= '\\') goto yy140; + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 1) { + goto yy152; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy137; + goto yy99; + } else { + if (yych <= '\f') goto yy137; + if (yych <= 0x1F) goto yy99; + goto yy137; + } + } else { + if (yych <= '/') { + if (yych <= '"') goto yy141; + if (yych <= '.') goto yy137; + goto yy154; + } else { + if (yych == '\\') goto yy140; + goto yy137; + } + } +yy161: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy139; + goto yy140; +yy168: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy139; + goto yy140; +yy171: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy172; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy172: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy173; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy173: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy174; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy174: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy175; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy175: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy176; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy176: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy177; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy177: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy137; + goto yy99; + } else { + if (yych <= 'F') goto yy137; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy137; + goto yy99; + } +yy178: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy179; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy179: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy180; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy180: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy137; + goto yy99; + } else { + if (yych <= 'F') goto yy137; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy137; + goto yy99; + } +yy181: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy182: + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych >= '\\') goto yy184; +yy183: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy196; +yy184: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy181; + goto yy99; + } else { + if (yych <= '\'') goto yy181; + if (yych <= '/') goto yy99; + goto yy189; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy187; + goto yy99; + } else { + if (yych <= 'U') goto yy186; + if (yych == '\\') goto yy181; + goto yy99; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy181; + if (yych <= 'e') goto yy99; + goto yy181; + } else { + if (yych == 'n') goto yy181; + if (yych <= 'q') goto yy99; + goto yy181; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy99; + if (yych <= 't') goto yy181; + } else { + if (yych <= 'v') goto yy181; + if (yych == 'x') goto yy188; + goto yy99; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy222; + goto yy99; + } else { + if (yych <= 'F') goto yy222; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy222; + goto yy99; + } +yy186: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy215; + goto yy99; + } else { + if (yych <= 'F') goto yy215; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy215; + goto yy99; + } +yy187: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy195; + goto yy184; +yy188: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy193; + goto yy99; + } else { + if (yych <= 'F') goto yy193; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy193; + goto yy99; + } +yy189: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\'') { + if (yych <= '\n') { + if (yych == '\t') goto yy181; + goto yy99; + } else { + if (yych <= '\f') goto yy181; + if (yych <= 0x1F) goto yy99; + if (yych <= '&') goto yy181; + goto yy191; + } + } else { + if (yych <= '>') { + if (yych <= '/') goto yy181; + if (yych >= '8') goto yy181; + } else { + if (yych <= '?') goto yy183; + if (yych == '\\') goto yy184; + goto yy181; + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy183; + goto yy184; +yy191: + ++YYCURSOR; +yy192: +#line 252 "cpp.re" + { BOOST_WAVE_RET(T_CHARLIT); } +#line 2542 "cpp_re.inc" +yy193: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + goto yy193; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + goto yy193; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych <= 'f') goto yy193; + goto yy181; + } + } + } +yy195: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych >= '\\') goto yy184; +yy196: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\'') { + if (yych <= '\n') { + if (yych == '\t') goto yy181; + goto yy99; + } else { + if (yych <= '\f') goto yy181; + if (yych <= 0x1F) goto yy99; + if (yych <= '&') goto yy181; + goto yy191; + } + } else { + if (yych <= '>') { + if (yych != '/') goto yy181; + } else { + if (yych <= '?') goto yy196; + if (yych == '\\') goto yy184; + goto yy181; + } + } +yy198: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '>') { + if (yych <= 0x1F) { + if (yych <= '\t') { + if (yych <= 0x08) goto yy99; + goto yy181; + } else { + if (yych <= '\n') goto yy99; + if (yych <= '\f') goto yy181; + goto yy99; + } + } else { + if (yych <= '\'') { + if (yych <= '&') goto yy181; + goto yy202; + } else { + if (yych <= '/') goto yy181; + if (yych <= '7') goto yy189; + goto yy181; + } + } + } else { + if (yych <= '\\') { + if (yych <= 'T') { + if (yych <= '?') goto yy203; + goto yy181; + } else { + if (yych <= 'U') goto yy201; + if (yych <= '[') goto yy181; + goto yy198; + } + } else { + if (yych <= 'u') { + if (yych <= 't') goto yy181; + } else { + if (yych == 'x') goto yy193; + goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + goto yy212; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + goto yy212; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych <= 'f') goto yy212; + goto yy181; + } + } + } +yy201: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + goto yy205; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + goto yy205; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych <= 'f') goto yy205; + goto yy181; + } + } + } +yy202: + yyaccept = 7; + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy192; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy183; + goto yy184; +yy203: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych >= '\\') goto yy184; + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\'') { + if (yych <= '\n') { + if (yych == '\t') goto yy181; + goto yy99; + } else { + if (yych <= '\f') goto yy181; + if (yych <= 0x1F) goto yy99; + if (yych <= '&') goto yy181; + goto yy191; + } + } else { + if (yych <= '>') { + if (yych == '/') goto yy198; + goto yy181; + } else { + if (yych <= '?') goto yy196; + if (yych == '\\') goto yy184; + goto yy181; + } + } +yy205: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy183; + goto yy184; +yy212: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy183; + goto yy184; +yy215: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy216; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy216: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy217; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy217: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy218; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy218: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy219; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy219: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy220; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy220: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy221; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy221: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy181; + goto yy99; + } else { + if (yych <= 'F') goto yy181; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy181; + goto yy99; + } +yy222: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy223; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy223: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy224; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy224: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy181; + goto yy99; + } else { + if (yych <= 'F') goto yy181; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy181; + goto yy99; + } +yy225: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '"') goto yy135; + goto yy109; +yy226: + yych = *++YYCURSOR; + if (yych == '\'') goto yy99; + goto yy182; +yy227: + ++YYCURSOR; +#line 227 "cpp.re" + { BOOST_WAVE_RET(T_GREATEREQUAL); } +#line 3175 "cpp_re.inc" +yy229: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy231; +#line 220 "cpp.re" + { BOOST_WAVE_RET(T_SHIFTRIGHT); } +#line 3181 "cpp_re.inc" +yy231: + ++YYCURSOR; +#line 221 "cpp.re" + { BOOST_WAVE_RET(T_SHIFTRIGHTASSIGN); } +#line 3186 "cpp_re.inc" +yy233: + ++YYCURSOR; +#line 223 "cpp.re" + { BOOST_WAVE_RET(T_EQUAL); } +#line 3191 "cpp_re.inc" +yy235: + ++YYCURSOR; +#line 224 "cpp.re" + { BOOST_WAVE_RET(T_NOTEQUAL); } +#line 3196 "cpp_re.inc" +yy237: + yych = *++YYCURSOR; + if (yych == '?') goto yy242; + goto yy99; +yy238: + ++YYCURSOR; +#line 230 "cpp.re" + { BOOST_WAVE_RET(T_OROR); } +#line 3205 "cpp_re.inc" +yy240: + ++YYCURSOR; +#line 216 "cpp.re" + { BOOST_WAVE_RET(T_ORASSIGN); } +#line 3210 "cpp_re.inc" +yy242: + yych = *++YYCURSOR; + if (yych != '!') goto yy99; + ++YYCURSOR; +#line 232 "cpp.re" + { BOOST_WAVE_RET(T_OROR_TRIGRAPH); } +#line 3217 "cpp_re.inc" +yy245: + ++YYCURSOR; +#line 228 "cpp.re" + { BOOST_WAVE_RET(T_ANDAND); } +#line 3222 "cpp_re.inc" +yy247: + ++YYCURSOR; +#line 214 "cpp.re" + { BOOST_WAVE_RET(T_ANDASSIGN); } +#line 3227 "cpp_re.inc" +yy249: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 8; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy252; + if (yych <= '`') goto yy251; + if (yych <= 'z') goto yy108; + } + } +yy251: +#line 192 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_XOR_ALT); } +#line 3254 "cpp_re.inc" +yy252: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'q') goto yy109; + yyaccept = 9; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy255: +#line 212 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_XORASSIGN_ALT); } +#line 3272 "cpp_re.inc" +yy256: + ++YYCURSOR; +#line 211 "cpp.re" + { BOOST_WAVE_RET(T_XORASSIGN); } +#line 3277 "cpp_re.inc" +yy258: + ++YYCURSOR; +#line 208 "cpp.re" + { BOOST_WAVE_RET(T_STARASSIGN); } +#line 3282 "cpp_re.inc" +yy260: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '*') goto yy266; +#line 248 "cpp.re" + { BOOST_WAVE_RET(T_ARROW); } +#line 3288 "cpp_re.inc" +yy262: + ++YYCURSOR; +#line 236 "cpp.re" + { BOOST_WAVE_RET(T_MINUSMINUS); } +#line 3293 "cpp_re.inc" +yy264: + ++YYCURSOR; +#line 207 "cpp.re" + { BOOST_WAVE_RET(T_MINUSASSIGN); } +#line 3298 "cpp_re.inc" +yy266: + ++YYCURSOR; +#line 239 "cpp.re" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + BOOST_WAVE_RET(T_ARROW); + } + else { + BOOST_WAVE_RET(T_ARROWSTAR); + } + } +#line 3311 "cpp_re.inc" +yy268: + ++YYCURSOR; +#line 235 "cpp.re" + { BOOST_WAVE_RET(T_PLUSPLUS); } +#line 3316 "cpp_re.inc" +yy270: + ++YYCURSOR; +#line 206 "cpp.re" + { BOOST_WAVE_RET(T_PLUSASSIGN); } +#line 3321 "cpp_re.inc" +yy272: + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 12) YYFILL(12); + yych = *YYCURSOR; +yy273: + if (yych <= 'h') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy272; + goto yy99; + } else { + if (yych <= '\f') goto yy272; + if (yych <= 0x1F) goto yy99; + goto yy272; + } + } else { + if (yych <= 'c') { + if (yych != '/') goto yy99; + } else { + if (yych <= 'd') goto yy281; + if (yych <= 'e') goto yy275; + goto yy99; + } + } + } else { + if (yych <= 'q') { + if (yych <= 'l') { + if (yych <= 'i') goto yy282; + if (yych <= 'k') goto yy99; + goto yy279; + } else { + if (yych == 'p') goto yy278; + goto yy99; + } + } else { + if (yych <= 'u') { + if (yych <= 'r') goto yy276; + if (yych <= 't') goto yy99; + goto yy280; + } else { + if (yych == 'w') goto yy277; + goto yy99; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == '*') goto yy389; + goto yy99; +yy275: + yych = *++YYCURSOR; + if (yych <= 'm') { + if (yych == 'l') goto yy365; + goto yy99; + } else { + if (yych <= 'n') goto yy366; + if (yych == 'r') goto yy367; + goto yy99; + } +yy276: + yych = *++YYCURSOR; + if (yych == 'e') goto yy359; + goto yy99; +yy277: + yych = *++YYCURSOR; + if (yych == 'a') goto yy352; + goto yy99; +yy278: + yych = *++YYCURSOR; + if (yych == 'r') goto yy346; + goto yy99; +yy279: + yych = *++YYCURSOR; + if (yych == 'i') goto yy342; + goto yy99; +yy280: + yych = *++YYCURSOR; + if (yych == 'n') goto yy337; + goto yy99; +yy281: + yych = *++YYCURSOR; + if (yych == 'e') goto yy331; + goto yy99; +yy282: + yych = *++YYCURSOR; + if (yych == 'f') goto yy290; + if (yych == 'n') goto yy289; + goto yy99; +yy283: + yych = *++YYCURSOR; + if (yych == '?') goto yy286; + goto yy99; +yy284: + ++YYCURSOR; +#line 153 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND); } +#line 3419 "cpp_re.inc" +yy286: + yych = *++YYCURSOR; + if (yych != '=') goto yy99; + ++YYCURSOR; +#line 154 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND_TRIGRAPH); } +#line 3426 "cpp_re.inc" +yy289: + yych = *++YYCURSOR; + if (yych == 'c') goto yy301; + goto yy99; +yy290: + yyaccept = 10; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy293; + if (yych == 'n') goto yy292; +yy291: +#line 301 "cpp.re" + { BOOST_WAVE_RET(T_PP_IF); } +#line 3439 "cpp_re.inc" +yy292: + yych = *++YYCURSOR; + if (yych == 'd') goto yy297; + goto yy99; +yy293: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'f') goto yy99; + ++YYCURSOR; +#line 302 "cpp.re" + { BOOST_WAVE_RET(T_PP_IFDEF); } +#line 3452 "cpp_re.inc" +yy297: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'f') goto yy99; + ++YYCURSOR; +#line 303 "cpp.re" + { BOOST_WAVE_RET(T_PP_IFNDEF); } +#line 3461 "cpp_re.inc" +yy301: + yych = *++YYCURSOR; + if (yych != 'l') goto yy99; + yych = *++YYCURSOR; + if (yych != 'u') goto yy99; + yych = *++YYCURSOR; + if (yych != 'd') goto yy99; + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yyaccept = 11; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '_') goto yy307; + goto yy309; +yy306: +#line 299 "cpp.re" + { BOOST_WAVE_RET(T_PP_INCLUDE); } +#line 3478 "cpp_re.inc" +yy307: + yych = *++YYCURSOR; + if (yych == 'n') goto yy328; + goto yy99; +yy308: + yyaccept = 11; + YYMARKER = ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; +yy309: + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy308; + goto yy306; + } else { + if (yych <= '\f') goto yy308; + if (yych <= 0x1F) goto yy306; + goto yy308; + } + } else { + if (yych <= '.') { + if (yych == '"') goto yy312; + goto yy306; + } else { + if (yych <= '/') goto yy310; + if (yych == '<') goto yy311; + goto yy306; + } + } +yy310: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == '*') goto yy321; + goto yy99; +yy311: + yych = *++YYCURSOR; + if (yych == '>') goto yy99; + goto yy318; +yy312: + yych = *++YYCURSOR; + if (yych == '"') goto yy99; + goto yy314; +yy313: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy314: + if (yybm[0+yych] & 8) { + goto yy313; + } + if (yych <= '!') goto yy99; + ++YYCURSOR; +#line 296 "cpp.re" + { BOOST_WAVE_RET(T_PP_QHEADER); } +#line 3534 "cpp_re.inc" +yy317: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy318: + if (yybm[0+yych] & 16) { + goto yy317; + } + if (yych <= '=') goto yy99; + ++YYCURSOR; +#line 293 "cpp.re" + { BOOST_WAVE_RET(T_PP_HHEADER); } +#line 3547 "cpp_re.inc" +yy321: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy321; + } + if (yych == '\r') goto yy323; + if (yych <= ')') goto yy99; + goto yy325; +yy323: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy321; + } + if (yych == '\r') goto yy323; + if (yych <= ')') goto yy99; +yy325: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy325; + } + if (yych <= '\r') { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy321; + } else { + if (yych <= 0x1F) goto yy99; + if (yych == '/') goto yy308; + goto yy321; + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy321; + } + if (yych == '\r') goto yy323; + if (yych <= ')') goto yy99; + goto yy325; +yy328: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'x') goto yy99; + yych = *++YYCURSOR; + if (yych == 't') goto yy308; + goto yy99; +yy331: + yych = *++YYCURSOR; + if (yych != 'f') goto yy99; + yych = *++YYCURSOR; + if (yych != 'i') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + ++YYCURSOR; +#line 307 "cpp.re" + { BOOST_WAVE_RET(T_PP_DEFINE); } +#line 3611 "cpp_re.inc" +yy337: + yych = *++YYCURSOR; + if (yych != 'd') goto yy99; + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'f') goto yy99; + ++YYCURSOR; +#line 308 "cpp.re" + { BOOST_WAVE_RET(T_PP_UNDEF); } +#line 3622 "cpp_re.inc" +yy342: + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + ++YYCURSOR; +#line 309 "cpp.re" + { BOOST_WAVE_RET(T_PP_LINE); } +#line 3631 "cpp_re.inc" +yy346: + yych = *++YYCURSOR; + if (yych != 'a') goto yy99; + yych = *++YYCURSOR; + if (yych != 'g') goto yy99; + yych = *++YYCURSOR; + if (yych != 'm') goto yy99; + yych = *++YYCURSOR; + if (yych != 'a') goto yy99; + ++YYCURSOR; +#line 311 "cpp.re" + { BOOST_WAVE_RET(T_PP_PRAGMA); } +#line 3644 "cpp_re.inc" +yy352: + yych = *++YYCURSOR; + if (yych != 'r') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + yych = *++YYCURSOR; + if (yych != 'i') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + yych = *++YYCURSOR; + if (yych != 'g') goto yy99; + ++YYCURSOR; +#line 313 "cpp.re" + { BOOST_WAVE_RET(T_PP_WARNING); } +#line 3659 "cpp_re.inc" +yy359: + yych = *++YYCURSOR; + if (yych != 'g') goto yy99; + yych = *++YYCURSOR; + if (yych != 'i') goto yy99; + yych = *++YYCURSOR; + if (yych != 'o') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + ++YYCURSOR; +#line 315 "cpp.re" + { BOOST_WAVE_RET(T_MSEXT_PP_REGION); } +#line 3672 "cpp_re.inc" +yy365: + yych = *++YYCURSOR; + if (yych == 'i') goto yy383; + if (yych == 's') goto yy384; + goto yy99; +yy366: + yych = *++YYCURSOR; + if (yych == 'd') goto yy372; + goto yy99; +yy367: + yych = *++YYCURSOR; + if (yych != 'r') goto yy99; + yych = *++YYCURSOR; + if (yych != 'o') goto yy99; + yych = *++YYCURSOR; + if (yych != 'r') goto yy99; + ++YYCURSOR; +#line 310 "cpp.re" + { BOOST_WAVE_RET(T_PP_ERROR); } +#line 3692 "cpp_re.inc" +yy372: + yych = *++YYCURSOR; + if (yych == 'i') goto yy373; + if (yych == 'r') goto yy374; + goto yy99; +yy373: + yych = *++YYCURSOR; + if (yych == 'f') goto yy381; + goto yy99; +yy374: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'g') goto yy99; + yych = *++YYCURSOR; + if (yych != 'i') goto yy99; + yych = *++YYCURSOR; + if (yych != 'o') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + ++YYCURSOR; +#line 316 "cpp.re" + { BOOST_WAVE_RET(T_MSEXT_PP_ENDREGION); } +#line 3716 "cpp_re.inc" +yy381: + ++YYCURSOR; +#line 306 "cpp.re" + { BOOST_WAVE_RET(T_PP_ENDIF); } +#line 3721 "cpp_re.inc" +yy383: + yych = *++YYCURSOR; + if (yych == 'f') goto yy387; + goto yy99; +yy384: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + ++YYCURSOR; +#line 304 "cpp.re" + { BOOST_WAVE_RET(T_PP_ELSE); } +#line 3732 "cpp_re.inc" +yy387: + ++YYCURSOR; +#line 305 "cpp.re" + { BOOST_WAVE_RET(T_PP_ELIF); } +#line 3737 "cpp_re.inc" +yy389: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\r') { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy389; + } else { + if (yych <= 0x1F) goto yy99; + if (yych == '*') goto yy393; + goto yy389; + } +yy391: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\r') { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy389; + goto yy391; + } else { + if (yych <= 0x1F) goto yy99; + if (yych != '*') goto yy389; + } +yy393: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy389; + if (yych >= 0x0E) goto yy99; + } else { + if (yych <= '*') { + if (yych <= ')') goto yy389; + goto yy393; + } else { + if (yych == '/') goto yy272; + goto yy389; + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\r') { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy389; + goto yy391; + } else { + if (yych <= 0x1F) goto yy99; + if (yych == '*') goto yy393; + goto yy389; + } +yy396: + ++YYCURSOR; +#line 165 "cpp.re" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + BOOST_WAVE_RET(T_COLON); + } + else { + BOOST_WAVE_RET(T_COLON_COLON); + } + } +#line 3803 "cpp_re.inc" +yy398: + ++YYCURSOR; +#line 149 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACKET_ALT); } +#line 3808 "cpp_re.inc" +yy400: + yyaccept = 12; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'e') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy273; + } else { + if (yych <= '\f') goto yy273; + if (yych >= ' ') goto yy273; + } + } else { + if (yych <= '.') { + if (yych == '%') goto yy406; + } else { + if (yych <= '/') goto yy273; + if (yych >= 'd') goto yy273; + } + } + } else { + if (yych <= 'p') { + if (yych <= 'k') { + if (yych == 'i') goto yy273; + } else { + if (yych <= 'l') goto yy273; + if (yych >= 'p') goto yy273; + } + } else { + if (yych <= 't') { + if (yych == 'r') goto yy273; + } else { + if (yych == 'v') goto yy401; + if (yych <= 'w') goto yy273; + } + } + } +yy401: +#line 151 "cpp.re" + { BOOST_WAVE_RET(T_POUND_ALT); } +#line 3848 "cpp_re.inc" +yy402: + ++YYCURSOR; +#line 210 "cpp.re" + { BOOST_WAVE_RET(T_PERCENTASSIGN); } +#line 3853 "cpp_re.inc" +yy404: + ++YYCURSOR; +#line 143 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACE_ALT); } +#line 3858 "cpp_re.inc" +yy406: + yych = *++YYCURSOR; + if (yych != ':') goto yy99; + ++YYCURSOR; +#line 157 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND_ALT); } +#line 3865 "cpp_re.inc" +yy409: + ++YYCURSOR; +#line 226 "cpp.re" + { BOOST_WAVE_RET(T_LESSEQUAL); } +#line 3870 "cpp_re.inc" +yy411: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy417; +#line 219 "cpp.re" + { BOOST_WAVE_RET(T_SHIFTLEFT); } +#line 3876 "cpp_re.inc" +yy413: + ++YYCURSOR; +#line 146 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACKET_ALT); } +#line 3881 "cpp_re.inc" +yy415: + ++YYCURSOR; +#line 140 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACE_ALT); } +#line 3886 "cpp_re.inc" +yy417: + ++YYCURSOR; +#line 222 "cpp.re" + { BOOST_WAVE_RET(T_SHIFTLEFTASSIGN); } +#line 3891 "cpp_re.inc" +yy419: + yych = *++YYCURSOR; + switch (yych) { + case '!': goto yy432; + case '\'': goto yy430; + case '(': goto yy424; + case ')': goto yy426; + case '-': goto yy434; + case '/': goto yy436; + case '<': goto yy420; + case '=': goto yy428; + case '>': goto yy422; + default: goto yy99; + } +yy420: + ++YYCURSOR; +#line 139 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACE_TRIGRAPH); } +#line 3910 "cpp_re.inc" +yy422: + ++YYCURSOR; +#line 142 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACE_TRIGRAPH); } +#line 3915 "cpp_re.inc" +yy424: + ++YYCURSOR; +#line 145 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACKET_TRIGRAPH); } +#line 3920 "cpp_re.inc" +yy426: + ++YYCURSOR; +#line 148 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACKET_TRIGRAPH); } +#line 3925 "cpp_re.inc" +yy428: + yyaccept = 13; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'c') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy273; + } else { + if (yych <= '\f') goto yy273; + if (yych >= ' ') goto yy273; + } + } else { + if (yych <= '.') { + if (yych == '#') goto yy449; + } else { + if (yych <= '/') goto yy273; + if (yych == '?') goto yy448; + } + } + } else { + if (yych <= 'p') { + if (yych <= 'i') { + if (yych <= 'e') goto yy273; + if (yych >= 'i') goto yy273; + } else { + if (yych == 'l') goto yy273; + if (yych >= 'p') goto yy273; + } + } else { + if (yych <= 't') { + if (yych == 'r') goto yy273; + } else { + if (yych == 'v') goto yy429; + if (yych <= 'w') goto yy273; + } + } + } +yy429: +#line 152 "cpp.re" + { BOOST_WAVE_RET(T_POUND_TRIGRAPH); } +#line 3966 "cpp_re.inc" +yy430: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy446; +#line 191 "cpp.re" + { BOOST_WAVE_RET(T_XOR_TRIGRAPH); } +#line 3972 "cpp_re.inc" +yy432: + yyaccept = 14; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '>') { + if (yych == '=') goto yy441; + } else { + if (yych <= '?') goto yy438; + if (yych == '|') goto yy439; + } +yy433: +#line 197 "cpp.re" + { BOOST_WAVE_RET(T_OR_TRIGRAPH); } +#line 3985 "cpp_re.inc" +yy434: + ++YYCURSOR; +#line 199 "cpp.re" + { BOOST_WAVE_RET(T_COMPL_TRIGRAPH); } +#line 3990 "cpp_re.inc" +yy436: + yyaccept = 15; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'U') goto yy100; + if (yych == 'u') goto yy98; +yy437: +#line 249 "cpp.re" + { BOOST_WAVE_RET(T_ANY_TRIGRAPH); } +#line 3999 "cpp_re.inc" +yy438: + yych = *++YYCURSOR; + if (yych == '?') goto yy443; + goto yy99; +yy439: + ++YYCURSOR; +#line 231 "cpp.re" + { BOOST_WAVE_RET(T_OROR_TRIGRAPH); } +#line 4008 "cpp_re.inc" +yy441: + ++YYCURSOR; +#line 218 "cpp.re" + { BOOST_WAVE_RET(T_ORASSIGN_TRIGRAPH); } +#line 4013 "cpp_re.inc" +yy443: + yych = *++YYCURSOR; + if (yych != '!') goto yy99; + ++YYCURSOR; +#line 234 "cpp.re" + { BOOST_WAVE_RET(T_OROR_TRIGRAPH); } +#line 4020 "cpp_re.inc" +yy446: + ++YYCURSOR; +#line 213 "cpp.re" + { BOOST_WAVE_RET(T_XORASSIGN_TRIGRAPH); } +#line 4025 "cpp_re.inc" +yy448: + yych = *++YYCURSOR; + if (yych == '?') goto yy451; + goto yy99; +yy449: + ++YYCURSOR; +#line 155 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND_TRIGRAPH); } +#line 4034 "cpp_re.inc" +yy451: + yych = *++YYCURSOR; + if (yych != '=') goto yy99; + ++YYCURSOR; +#line 156 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND_TRIGRAPH); } +#line 4041 "cpp_re.inc" +yy454: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'a': goto yy455; + case 'b': goto yy456; + case 'c': goto yy457; + case 'd': goto yy458; + case 'e': goto yy507; + case 'f': goto yy505; + case 'i': goto yy504; + case 'l': goto yy508; + case 's': goto yy461; + case 't': goto yy506; + default: goto yy109; + } +yy455: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy501; + goto yy109; +yy456: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy496; + goto yy109; +yy457: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy491; + goto yy109; +yy458: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy483; + goto yy109; +yy459: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy475; + goto yy109; +yy460: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy469; + goto yy109; +yy461: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 16; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy468: +#line 130 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_STDCALL : T_IDENTIFIER); } +#line 4117 "cpp_re.inc" +yy469: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; +yy470: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 17; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy474: +#line 135 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INLINE : T_IDENTIFIER); } +#line 4142 "cpp_re.inc" +yy475: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 18; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy482: +#line 129 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_FASTCALL : T_IDENTIFIER); } +#line 4172 "cpp_re.inc" +yy483: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 19; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy490: +#line 127 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_DECLSPEC : T_IDENTIFIER); } +#line 4202 "cpp_re.inc" +yy491: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 20; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy495: +#line 128 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_CDECL : T_IDENTIFIER); } +#line 4223 "cpp_re.inc" +yy496: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 21; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy500: +#line 126 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_BASED : T_IDENTIFIER); } +#line 4244 "cpp_re.inc" +yy501: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'm') goto yy109; + yyaccept = 22; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy503: +#line 136 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_ASM : T_IDENTIFIER); } +#line 4259 "cpp_re.inc" +yy504: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy530; + goto yy109; +yy505: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy475; + if (yych == 'i') goto yy523; + goto yy109; +yy506: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy520; + goto yy109; +yy507: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'x') goto yy514; + goto yy109; +yy508: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'v') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 23; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy513: +#line 134 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_LEAVE : T_IDENTIFIER); } +#line 4304 "cpp_re.inc" +yy514: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 24; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy519: +#line 132 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_EXCEPT : T_IDENTIFIER); } +#line 4328 "cpp_re.inc" +yy520: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'y') goto yy109; + yyaccept = 25; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy522: +#line 131 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_TRY : T_IDENTIFIER); } +#line 4343 "cpp_re.inc" +yy523: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'y') goto yy109; + yyaccept = 26; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy529: +#line 133 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_FINALLY : T_IDENTIFIER); } +#line 4370 "cpp_re.inc" +yy530: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy470; + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case '1': goto yy532; + case '3': goto yy533; + case '6': goto yy534; + case '8': goto yy535; + default: goto yy109; + } +yy532: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '6') goto yy541; + goto yy109; +yy533: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '2') goto yy539; + goto yy109; +yy534: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '4') goto yy537; + goto yy109; +yy535: + yyaccept = 27; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy536: +#line 122 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INT8 : T_IDENTIFIER); } +#line 4411 "cpp_re.inc" +yy537: + yyaccept = 28; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy538: +#line 125 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INT64 : T_IDENTIFIER); } +#line 4423 "cpp_re.inc" +yy539: + yyaccept = 29; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy540: +#line 124 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INT32 : T_IDENTIFIER); } +#line 4435 "cpp_re.inc" +yy541: + yyaccept = 30; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy542: +#line 123 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INT16 : T_IDENTIFIER); } +#line 4447 "cpp_re.inc" +yy543: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'h') goto yy549; + goto yy109; +yy544: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 31; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy548: +#line 120 "cpp.re" + { BOOST_WAVE_RET(T_WHILE); } +#line 4473 "cpp_re.inc" +yy549: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 32; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy554: +#line 119 "cpp.re" + { BOOST_WAVE_RET(T_WCHART); } +#line 4497 "cpp_re.inc" +yy555: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy567; + goto yy109; +yy556: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy557; + if (yych == 'l') goto yy558; + goto yy109; +yy557: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy565; + goto yy109; +yy558: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 33; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy564: +#line 118 "cpp.re" + { BOOST_WAVE_RET(T_VOLATILE); } +#line 4540 "cpp_re.inc" +yy565: + yyaccept = 34; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy566: +#line 117 "cpp.re" + { BOOST_WAVE_RET(T_VOID); } +#line 4552 "cpp_re.inc" +yy567: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 35; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy572: +#line 116 "cpp.re" + { BOOST_WAVE_RET(T_VIRTUAL); } +#line 4576 "cpp_re.inc" +yy573: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '"') goto yy129; + if (yych == 'R') goto yy128; + goto yy109; +yy574: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy580; + if (yych == 's') goto yy581; + goto yy109; +yy575: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'g') goto yy109; + yyaccept = 36; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy579: +#line 115 "cpp.re" + { BOOST_WAVE_RET(T_USING); } +#line 4609 "cpp_re.inc" +yy580: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy588; + goto yy109; +yy581: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'g') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 37; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy587: +#line 114 "cpp.re" + { BOOST_WAVE_RET(T_UNSIGNED); } +#line 4641 "cpp_re.inc" +yy588: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 38; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy590: +#line 113 "cpp.re" + { BOOST_WAVE_RET(T_UNION); } +#line 4656 "cpp_re.inc" +yy591: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'm') goto yy631; + goto yy109; +yy592: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy614; + if (yych == 'r') goto yy615; + goto yy109; +yy593: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy609; + if (yych == 'y') goto yy610; + goto yy109; +yy594: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'h') { + if (yych != 'd') goto yy109; + } else { + if (yych <= 'i') goto yy598; + if (yych == 'n') goto yy599; + goto yy109; + } + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy606; + goto yy109; +yy598: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy604; + goto yy109; +yy599: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'm') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 39; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy603: +#line 112 "cpp.re" + { BOOST_WAVE_RET(T_TYPENAME); } +#line 4719 "cpp_re.inc" +yy604: + yyaccept = 40; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy605: +#line 111 "cpp.re" + { BOOST_WAVE_RET(T_TYPEID); } +#line 4731 "cpp_re.inc" +yy606: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'f') goto yy109; + yyaccept = 41; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy608: +#line 110 "cpp.re" + { BOOST_WAVE_RET(T_TYPEDEF); } +#line 4746 "cpp_re.inc" +yy609: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy612; + goto yy109; +yy610: + yyaccept = 42; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy611: +#line 109 "cpp.re" + { BOOST_WAVE_RET(T_TRY); } +#line 4763 "cpp_re.inc" +yy612: + yyaccept = 43; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy613: +#line 108 "cpp.re" + { BOOST_WAVE_RET(T_TRUE); } +#line 4775 "cpp_re.inc" +yy614: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy629; + goto yy109; +yy615: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy616; + if (yych == 'o') goto yy617; + goto yy109; +yy616: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy620; + goto yy109; +yy617: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'w') goto yy109; + yyaccept = 44; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy619: +#line 107 "cpp.re" + { BOOST_WAVE_RET(T_THROW); } +#line 4806 "cpp_re.inc" +yy620: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 45; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy628: +#line 106 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_THREADLOCAL : T_IDENTIFIER); } +#line 4839 "cpp_re.inc" +yy629: + yyaccept = 46; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy630: +#line 105 "cpp.re" + { BOOST_WAVE_RET(T_THIS); } +#line 4851 "cpp_re.inc" +yy631: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 47; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy637: +#line 104 "cpp.re" + { BOOST_WAVE_RET(T_TEMPLATE); } +#line 4878 "cpp_re.inc" +yy638: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy680; + goto yy109; +yy639: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'g') goto yy670; + if (yych == 'z') goto yy671; + goto yy109; +yy640: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy647; + if (yych == 'r') goto yy648; + goto yy109; +yy641: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'h') goto yy109; + yyaccept = 48; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy646: +#line 103 "cpp.re" + { BOOST_WAVE_RET(T_SWITCH); } +#line 4919 "cpp_re.inc" +yy647: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 't') goto yy653; + goto yy109; +yy648: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 49; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy652: +#line 102 "cpp.re" + { BOOST_WAVE_RET(T_STRUCT); } +#line 4945 "cpp_re.inc" +yy653: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 50; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy657; + if (yych <= '`') goto yy656; + if (yych <= 'z') goto yy108; + } + } +yy656: +#line 99 "cpp.re" + { BOOST_WAVE_RET(T_STATIC); } +#line 4975 "cpp_re.inc" +yy657: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy658; + if (yych == 'c') goto yy659; + goto yy109; +yy658: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy664; + goto yy109; +yy659: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 51; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy663: +#line 100 "cpp.re" + { BOOST_WAVE_RET(T_STATICCAST); } +#line 5007 "cpp_re.inc" +yy664: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 52; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy669: +#line 101 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_STATICASSERT : T_IDENTIFIER); } +#line 5031 "cpp_re.inc" +yy670: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy676; + goto yy109; +yy671: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'f') goto yy109; + yyaccept = 53; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy675: +#line 98 "cpp.re" + { BOOST_WAVE_RET(T_SIZEOF); } +#line 5057 "cpp_re.inc" +yy676: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 54; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy679: +#line 97 "cpp.re" + { BOOST_WAVE_RET(T_SIGNED); } +#line 5075 "cpp_re.inc" +yy680: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 55; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy683: +#line 96 "cpp.re" + { BOOST_WAVE_RET(T_SHORT); } +#line 5093 "cpp_re.inc" +yy684: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'h') { + if (yych != 'g') goto yy109; + } else { + if (yych <= 'i') goto yy686; + if (yych == 't') goto yy687; + goto yy109; + } + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy706; + goto yy109; +yy686: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy692; + goto yy109; +yy687: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 56; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy691: +#line 95 "cpp.re" + { BOOST_WAVE_RET(T_RETURN); } +#line 5133 "cpp_re.inc" +yy692: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 57; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy705: +#line 94 "cpp.re" + { BOOST_WAVE_RET(T_REINTERPRETCAST); } +#line 5181 "cpp_re.inc" +yy706: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 58; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy711: +#line 93 "cpp.re" + { BOOST_WAVE_RET(T_REGISTER); } +#line 5205 "cpp_re.inc" +yy712: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy719; + if (yych == 'o') goto yy720; + goto yy109; +yy713: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'b') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 59; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy718: +#line 92 "cpp.re" + { BOOST_WAVE_RET(T_PUBLIC); } +#line 5235 "cpp_re.inc" +yy719: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'v') goto yy728; + goto yy109; +yy720: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 60; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy727: +#line 91 "cpp.re" + { BOOST_WAVE_RET(T_PROTECTED); } +#line 5270 "cpp_re.inc" +yy728: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 61; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy732: +#line 90 "cpp.re" + { BOOST_WAVE_RET(T_PRIVATE); } +#line 5291 "cpp_re.inc" +yy733: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy740; + goto yy109; +yy734: + yyaccept = 62; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy736; + if (yych <= '`') goto yy735; + if (yych <= 'z') goto yy108; + } + } +yy735: +#line 233 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_OROR_ALT); } +#line 5320 "cpp_re.inc" +yy736: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'q') goto yy109; + yyaccept = 63; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy739: +#line 217 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ORASSIGN_ALT); } +#line 5338 "cpp_re.inc" +yy740: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 64; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy746: +#line 89 "cpp.re" + { BOOST_WAVE_RET(T_OPERATOR); } +#line 5365 "cpp_re.inc" +yy747: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'm') goto yy772; + goto yy109; +yy748: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'w') goto yy770; + goto yy109; +yy749: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy757; + if (yych == 't') goto yy758; + goto yy109; +yy750: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 65; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy756: +#line 88 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_NULLPTR : T_IDENTIFIER); } +#line 5408 "cpp_re.inc" +yy757: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'x') goto yy764; + goto yy109; +yy758: + yyaccept = 66; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy760; + if (yych <= '`') goto yy759; + if (yych <= 'z') goto yy108; + } + } +yy759: +#line 202 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_NOT_ALT); } +#line 5437 "cpp_re.inc" +yy760: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'q') goto yy109; + yyaccept = 67; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy763: +#line 225 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_NOTEQUAL_ALT); } +#line 5455 "cpp_re.inc" +yy764: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 68; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy769: +#line 87 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_NOEXCEPT : T_IDENTIFIER); } +#line 5479 "cpp_re.inc" +yy770: + yyaccept = 69; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy771: +#line 86 "cpp.re" + { BOOST_WAVE_RET(T_NEW); } +#line 5491 "cpp_re.inc" +yy772: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 70; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy779: +#line 85 "cpp.re" + { BOOST_WAVE_RET(T_NAMESPACE); } +#line 5521 "cpp_re.inc" +yy780: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'b') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 71; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy786: +#line 84 "cpp.re" + { BOOST_WAVE_RET(T_MUTABLE); } +#line 5548 "cpp_re.inc" +yy787: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'g') goto yy109; + yyaccept = 72; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy790: +#line 83 "cpp.re" + { BOOST_WAVE_RET(T_LONG); } +#line 5566 "cpp_re.inc" +yy791: + yyaccept = 73; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy792: +#line 79 "cpp.re" + { BOOST_WAVE_RET(T_IF); } +#line 5578 "cpp_re.inc" +yy793: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'p') goto yy802; + goto yy109; +yy794: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy795; + if (yych == 't') goto yy796; + goto yy109; +yy795: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy798; + goto yy109; +yy796: + yyaccept = 74; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy797: +#line 82 "cpp.re" + { BOOST_WAVE_RET(T_INT); } +#line 5606 "cpp_re.inc" +yy798: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 75; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy801: +#line 81 "cpp.re" + { BOOST_WAVE_RET(T_INLINE); } +#line 5624 "cpp_re.inc" +yy802: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 76; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy806: +#line 80 "cpp.re" + { BOOST_WAVE_RET(s->enable_import_keyword ? T_IMPORT : T_IDENTIFIER); } +#line 5645 "cpp_re.inc" +yy807: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 77; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy810: +#line 78 "cpp.re" + { BOOST_WAVE_RET(T_GOTO); } +#line 5663 "cpp_re.inc" +yy811: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy826; + goto yy109; +yy812: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy822; + goto yy109; +yy813: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy820; + goto yy109; +yy814: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 78; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy819: +#line 77 "cpp.re" + { BOOST_WAVE_RET(T_FRIEND); } +#line 5702 "cpp_re.inc" +yy820: + yyaccept = 79; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy821: +#line 76 "cpp.re" + { BOOST_WAVE_RET(T_FOR); } +#line 5714 "cpp_re.inc" +yy822: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 80; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy825: +#line 75 "cpp.re" + { BOOST_WAVE_RET(T_FLOAT); } +#line 5732 "cpp_re.inc" +yy826: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 81; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy829: +#line 74 "cpp.re" + { BOOST_WAVE_RET(T_FALSE); } +#line 5750 "cpp_re.inc" +yy830: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy852; + goto yy109; +yy831: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy849; + goto yy109; +yy832: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'p') goto yy833; + if (yych == 't') goto yy834; + goto yy109; +yy833: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy839; + if (yych == 'o') goto yy840; + goto yy109; +yy834: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 82; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy838: +#line 73 "cpp.re" + { BOOST_WAVE_RET(T_EXTERN); } +#line 5793 "cpp_re.inc" +yy839: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy844; + goto yy109; +yy840: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 83; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy843: +#line 72 "cpp.re" + { BOOST_WAVE_RET(T_EXPORT); } +#line 5816 "cpp_re.inc" +yy844: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 84; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy848: +#line 71 "cpp.re" + { BOOST_WAVE_RET(T_EXPLICIT); } +#line 5837 "cpp_re.inc" +yy849: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'm') goto yy109; + yyaccept = 85; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy851: +#line 70 "cpp.re" + { BOOST_WAVE_RET(T_ENUM); } +#line 5852 "cpp_re.inc" +yy852: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 86; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy854: +#line 69 "cpp.re" + { BOOST_WAVE_RET(T_ELSE); } +#line 5867 "cpp_re.inc" +yy855: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'e') { + if (yych == 'c') goto yy875; + goto yy109; + } else { + if (yych <= 'f') goto yy876; + if (yych == 'l') goto yy877; + goto yy109; + } +yy856: + yyaccept = 87; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'Z') { + if (yych <= '9') { + if (yych == '$') goto yy108; + if (yych >= '0') goto yy108; + } else { + if (yych == '?') goto yy111; + if (yych >= 'A') goto yy108; + } + } else { + if (yych <= '_') { + if (yych == '\\') goto yy110; + if (yych >= '_') goto yy108; + } else { + if (yych <= 't') { + if (yych >= 'a') goto yy108; + } else { + if (yych <= 'u') goto yy870; + if (yych <= 'z') goto yy108; + } + } + } +yy857: +#line 66 "cpp.re" + { BOOST_WAVE_RET(T_DO); } +#line 5906 "cpp_re.inc" +yy858: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'm') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 88; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy869: +#line 68 "cpp.re" + { BOOST_WAVE_RET(T_DYNAMICCAST); } +#line 5948 "cpp_re.inc" +yy870: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'b') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 89; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy874: +#line 67 "cpp.re" + { BOOST_WAVE_RET(T_DOUBLE); } +#line 5969 "cpp_re.inc" +yy875: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy887; + goto yy109; +yy876: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy882; + goto yy109; +yy877: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 90; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy881: +#line 65 "cpp.re" + { BOOST_WAVE_RET(T_DELETE); } +#line 6000 "cpp_re.inc" +yy882: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 91; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy886: +#line 64 "cpp.re" + { BOOST_WAVE_RET(T_DEFAULT); } +#line 6021 "cpp_re.inc" +yy887: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'y') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 92; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy892: +#line 63 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_DECLTYPE : T_IDENTIFIER); } +#line 6045 "cpp_re.inc" +yy893: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'r') goto yy109; + if (yych <= 's') goto yy939; + if (yych <= 't') goto yy940; + goto yy109; +yy894: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy926; + goto yy109; +yy895: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy922; + goto yy109; +yy896: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'l') goto yy109; + if (yych <= 'm') goto yy898; + if (yych >= 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'r') goto yy109; + if (yych <= 's') goto yy902; + if (yych <= 't') goto yy903; + goto yy109; +yy898: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 93; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy901: +#line 200 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_COMPL_ALT); } +#line 6092 "cpp_re.inc" +yy902: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 't') goto yy909; + goto yy109; +yy903: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 94; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy908: +#line 62 "cpp.re" + { BOOST_WAVE_RET(T_CONTINUE); } +#line 6121 "cpp_re.inc" +yy909: + yyaccept = 95; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'Z') { + if (yych <= '9') { + if (yych == '$') goto yy108; + if (yych >= '0') goto yy108; + } else { + if (yych == '?') goto yy111; + if (yych >= 'A') goto yy108; + } + } else { + if (yych <= '_') { + if (yych == '\\') goto yy110; + if (yych >= '_') goto yy911; + } else { + if (yych <= 'd') { + if (yych >= 'a') goto yy108; + } else { + if (yych <= 'e') goto yy912; + if (yych <= 'z') goto yy108; + } + } + } +yy910: +#line 59 "cpp.re" + { BOOST_WAVE_RET(T_CONST); } +#line 6149 "cpp_re.inc" +yy911: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'c') goto yy917; + goto yy109; +yy912: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'x') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 96; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy916: +#line 60 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_CONSTEXPR : T_IDENTIFIER); } +#line 6175 "cpp_re.inc" +yy917: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 97; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy921: +#line 61 "cpp.re" + { BOOST_WAVE_RET(T_CONSTCAST); } +#line 6196 "cpp_re.inc" +yy922: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 98; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy925: +#line 58 "cpp.re" + { BOOST_WAVE_RET(T_CLASS); } +#line 6214 "cpp_re.inc" +yy926: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 99; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '>') { + if (yych <= '0') { + if (yych == '$') goto yy108; + if (yych >= '0') goto yy108; + } else { + if (yych <= '2') { + if (yych <= '1') goto yy929; + goto yy108; + } else { + if (yych <= '3') goto yy930; + if (yych <= '9') goto yy108; + } + } + } else { + if (yych <= '\\') { + if (yych <= '@') { + if (yych <= '?') goto yy111; + } else { + if (yych <= 'Z') goto yy108; + if (yych >= '\\') goto yy110; + } + } else { + if (yych <= '_') { + if (yych >= '_') goto yy108; + } else { + if (yych <= '`') goto yy928; + if (yych <= 'z') goto yy108; + } + } + } +yy928: +#line 55 "cpp.re" + { BOOST_WAVE_RET(T_CHAR); } +#line 6254 "cpp_re.inc" +yy929: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '6') goto yy935; + goto yy109; +yy930: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '2') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 100; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy934: +#line 57 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_CHAR32_T : T_IDENTIFIER); } +#line 6280 "cpp_re.inc" +yy935: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 101; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy938: +#line 56 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_CHAR16_T : T_IDENTIFIER); } +#line 6298 "cpp_re.inc" +yy939: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy944; + goto yy109; +yy940: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'h') goto yy109; + yyaccept = 102; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy943: +#line 54 "cpp.re" + { BOOST_WAVE_RET(T_CATCH); } +#line 6321 "cpp_re.inc" +yy944: + yyaccept = 103; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy945: +#line 53 "cpp.re" + { BOOST_WAVE_RET(T_CASE); } +#line 6333 "cpp_re.inc" +yy946: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 't') goto yy956; + goto yy109; +yy947: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy953; + goto yy109; +yy948: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'k') goto yy109; + yyaccept = 104; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy952: +#line 52 "cpp.re" + { BOOST_WAVE_RET(T_BREAK); } +#line 6364 "cpp_re.inc" +yy953: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 105; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy955: +#line 51 "cpp.re" + { BOOST_WAVE_RET(T_BOOL); } +#line 6379 "cpp_re.inc" +yy956: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy957; + if (yych == 'o') goto yy958; + goto yy109; +yy957: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy961; + goto yy109; +yy958: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 106; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy960: +#line 196 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_OR_ALT); } +#line 6405 "cpp_re.inc" +yy961: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 107; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy963: +#line 194 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_AND_ALT); } +#line 6420 "cpp_re.inc" +yy964: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy979; + goto yy109; +yy965: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy973; + goto yy109; +yy966: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'm') goto yy971; + goto yy109; +yy967: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 108; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy970: +#line 50 "cpp.re" + { BOOST_WAVE_RET(T_AUTO); } +#line 6453 "cpp_re.inc" +yy971: + yyaccept = 109; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy972: +#line 49 "cpp.re" + { BOOST_WAVE_RET(T_ASM); } +#line 6465 "cpp_re.inc" +yy973: + yyaccept = 110; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy975; + if (yych <= '`') goto yy974; + if (yych <= 'z') goto yy108; + } + } +yy974: +#line 229 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ANDAND_ALT); } +#line 6489 "cpp_re.inc" +yy975: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'q') goto yy109; + yyaccept = 111; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy978: +#line 215 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ANDASSIGN_ALT); } +#line 6507 "cpp_re.inc" +yy979: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'g') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy982; + if (yych == 'o') goto yy983; + goto yy109; +yy982: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy986; + goto yy109; +yy983: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'f') goto yy109; + yyaccept = 112; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy985: +#line 48 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_ALIGNOF : T_IDENTIFIER); } +#line 6539 "cpp_re.inc" +yy986: + yyaccept = 113; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy987: +#line 47 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_ALIGNAS : T_IDENTIFIER); } +#line 6551 "cpp_re.inc" +yy988: + ++YYCURSOR; +#line 176 "cpp.re" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + BOOST_WAVE_RET(T_DOT); + } + else { + BOOST_WAVE_RET(T_DOTSTAR); + } + } +#line 6564 "cpp_re.inc" +yy990: + yych = *++YYCURSOR; + if (yych == '.') goto yy992; + goto yy99; +yy991: + yych = *++YYCURSOR; + goto yy7; +yy992: + ++YYCURSOR; +#line 162 "cpp.re" + { BOOST_WAVE_RET(T_ELLIPSIS); } +#line 6576 "cpp_re.inc" +yy994: + ++YYCURSOR; +#line 209 "cpp.re" + { BOOST_WAVE_RET(T_DIVIDEASSIGN); } +#line 6581 "cpp_re.inc" +yy996: + ++YYCURSOR; +#line 44 "cpp.re" + { goto cppcomment; } +#line 6586 "cpp_re.inc" +yy998: + ++YYCURSOR; +#line 43 "cpp.re" + { goto ccomment; } +#line 6591 "cpp_re.inc" +} +#line 348 "cpp.re" + + +ccomment: + +#line 6598 "cpp_re.inc" +{ + YYCTYPE yych; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= '\f') { + if (yych <= 0x08) { + if (yych <= 0x00) goto yy1009; + goto yy1011; + } else { + if (yych == '\n') goto yy1004; + goto yy1007; + } + } else { + if (yych <= 0x1F) { + if (yych <= '\r') goto yy1006; + goto yy1011; + } else { + if (yych != '*') goto yy1008; + } + } + ++YYCURSOR; + if ((yych = *YYCURSOR) == '/') goto yy1014; +yy1003: +#line 363 "cpp.re" + { goto ccomment; } +#line 6624 "cpp_re.inc" +yy1004: + ++YYCURSOR; +yy1005: +#line 355 "cpp.re" + { + /*if(cursor == s->eof) BOOST_WAVE_RET(T_EOF);*/ + /*s->tok = cursor; */ + s->line += count_backslash_newlines(s, cursor) +1; + cursor.column = 1; + goto ccomment; + } +#line 6636 "cpp_re.inc" +yy1006: + yych = *++YYCURSOR; + if (yych == '\n') goto yy1013; + goto yy1005; +yy1007: + yych = *++YYCURSOR; + goto yy1003; +yy1008: + yych = *++YYCURSOR; + goto yy1003; +yy1009: + ++YYCURSOR; +#line 366 "cpp.re" + { + if(cursor == s->eof) + { + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_warning, + "Unterminated 'C' style comment"); + } + else + { + --YYCURSOR; // next call returns T_EOF + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character: '\\000' in input stream"); + } + } +#line 6665 "cpp_re.inc" +yy1011: + ++YYCURSOR; +#line 383 "cpp.re" + { + // flag the error + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\%03o' in input stream", *--YYCURSOR); + } +#line 6675 "cpp_re.inc" +yy1013: + yych = *++YYCURSOR; + goto yy1005; +yy1014: + ++YYCURSOR; +#line 352 "cpp.re" + { BOOST_WAVE_RET(T_CCOMMENT); } +#line 6683 "cpp_re.inc" +} +#line 389 "cpp.re" + + +cppcomment: + +#line 6690 "cpp_re.inc" +{ + YYCTYPE yych; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= '\n') { + if (yych <= 0x00) goto yy1024; + if (yych <= 0x08) goto yy1026; + if (yych <= '\t') goto yy1021; + } else { + if (yych <= '\f') goto yy1021; + if (yych <= '\r') goto yy1020; + if (yych <= 0x1F) goto yy1026; + goto yy1023; + } + ++YYCURSOR; +yy1019: +#line 394 "cpp.re" + { + /*if(cursor == s->eof) BOOST_WAVE_RET(T_EOF); */ + /*s->tok = cursor; */ + s->line++; + cursor.column = 1; + BOOST_WAVE_RET(T_CPPCOMMENT); + } +#line 6715 "cpp_re.inc" +yy1020: + yych = *++YYCURSOR; + if (yych == '\n') goto yy1028; + goto yy1019; +yy1021: + ++YYCURSOR; +yy1022: +#line 402 "cpp.re" + { goto cppcomment; } +#line 6725 "cpp_re.inc" +yy1023: + yych = *++YYCURSOR; + goto yy1022; +yy1024: + ++YYCURSOR; +#line 405 "cpp.re" + { + if (s->eof && cursor != s->eof) + { + --YYCURSOR; // next call returns T_EOF + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\000' in input stream"); + } + + --YYCURSOR; // next call returns T_EOF + if (!s->single_line_only) + { + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_warning, + "Unterminated 'C++' style comment"); + } + BOOST_WAVE_RET(T_CPPCOMMENT); + } +#line 6750 "cpp_re.inc" +yy1026: + ++YYCURSOR; +#line 425 "cpp.re" + { + // flag the error + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\%03o' in input stream", *--YYCURSOR); + } +#line 6760 "cpp_re.inc" +yy1028: + ++YYCURSOR; + yych = *YYCURSOR; + goto yy1019; +} +#line 431 "cpp.re" + + +/* this subscanner is called whenever a pp_number has been started */ +pp_number: +{ + cursor = uchar_wrapper(s->tok = s->cur, s->column = s->curr_column); + marker = uchar_wrapper(s->ptr); + limit = uchar_wrapper(s->lim); + + if (s->detect_pp_numbers) { + +#line 6778 "cpp_re.inc" +{ + YYCTYPE yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 64, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 64, 0, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 0, 0, 0, 0, 0, 0, + 0, 64, 64, 64, 64, 128, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 0, 0, 0, 0, 64, + 0, 64, 64, 64, 64, 128, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych == '.') goto yy1032; + if (yych <= '/') goto yy1031; + if (yych <= '9') goto yy1033; +yy1031: + YYCURSOR = YYMARKER; + goto yy1035; +yy1032: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; +yy1033: + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy1033; + } + if (yych <= 'Z') { + if (yych == '?') goto yy1039; + if (yych >= 'A') goto yy1036; + } else { + if (yych <= '\\') { + if (yych >= '\\') goto yy1038; + } else { + if (yych == 'e') goto yy1036; + } + } +yy1035: +#line 443 "cpp.re" + { BOOST_WAVE_RET(T_PP_NUMBER); } +#line 6847 "cpp_re.inc" +yy1036: + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1036; + } + if (yych <= '>') { + if (yych <= '+') { + if (yych == '$') goto yy1033; + if (yych <= '*') goto yy1035; + goto yy1033; + } else { + if (yych <= '.') { + if (yych <= ',') goto yy1035; + goto yy1033; + } else { + if (yych <= '/') goto yy1035; + if (yych <= '9') goto yy1033; + goto yy1035; + } + } + } else { + if (yych <= '\\') { + if (yych <= '@') { + if (yych <= '?') goto yy1039; + goto yy1035; + } else { + if (yych <= 'Z') goto yy1033; + if (yych <= '[') goto yy1035; + } + } else { + if (yych <= '_') { + if (yych <= '^') goto yy1035; + goto yy1033; + } else { + if (yych <= '`') goto yy1035; + if (yych <= 'z') goto yy1033; + goto yy1035; + } + } + } +yy1038: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == 'U') goto yy1042; + if (yych == 'u') goto yy1041; + goto yy1031; +yy1039: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych != '?') goto yy1031; + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == '/') goto yy1038; + goto yy1031; +yy1041: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych <= '9') goto yy1050; + goto yy1031; + } else { + if (yych <= 'F') goto yy1050; + if (yych <= '`') goto yy1031; + if (yych <= 'f') goto yy1050; + goto yy1031; + } +yy1042: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1043; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1043: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1044; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1044: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1045; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1045: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1046; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1046: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1047; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1047: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1048; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1048: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1049; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1049: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych <= '9') goto yy1033; + goto yy1031; + } else { + if (yych <= 'F') goto yy1033; + if (yych <= '`') goto yy1031; + if (yych <= 'f') goto yy1033; + goto yy1031; + } +yy1050: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1051; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1051: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1052; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1052: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych <= '9') goto yy1033; + goto yy1031; + } else { + if (yych <= 'F') goto yy1033; + if (yych <= '`') goto yy1031; + if (yych <= 'f') goto yy1033; + goto yy1031; + } +} +#line 444 "cpp.re" + + } + else { + +#line 7063 "cpp_re.inc" +{ + YYCTYPE yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 224, 224, 224, 224, 224, 224, 224, 224, + 160, 160, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; + if (yych <= '/') { + if (yych == '.') goto yy1060; + } else { + if (yych <= '0') goto yy1056; + if (yych <= '9') goto yy1058; + } +yy1055: + YYCURSOR = YYMARKER; + if (yyaccept <= 0) { + goto yy1057; + } else { + goto yy1063; + } +yy1056: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy1075; + } + if (yych <= 'E') { + if (yych <= '/') { + if (yych == '.') goto yy1061; + } else { + if (yych <= '9') goto yy1078; + if (yych >= 'E') goto yy1071; + } + } else { + if (yych <= 'd') { + if (yych == 'X') goto yy1077; + } else { + if (yych <= 'e') goto yy1071; + if (yych == 'x') goto yy1077; + } + } +yy1057: +#line 451 "cpp.re" + { goto integer_suffix; } +#line 7140 "cpp_re.inc" +yy1058: + yyaccept = 0; + YYMARKER = ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy1058; + } + if (yych <= 'D') { + if (yych == '.') goto yy1061; + goto yy1057; + } else { + if (yych <= 'E') goto yy1071; + if (yych == 'e') goto yy1071; + goto yy1057; + } +yy1060: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1055; + if (yych >= ':') goto yy1055; +yy1061: + yyaccept = 1; + YYMARKER = ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yych <= 'K') { + if (yych <= 'D') { + if (yych <= '/') goto yy1063; + if (yych <= '9') goto yy1061; + } else { + if (yych <= 'E') goto yy1064; + if (yych <= 'F') goto yy1065; + } + } else { + if (yych <= 'e') { + if (yych <= 'L') goto yy1066; + if (yych >= 'e') goto yy1064; + } else { + if (yych <= 'f') goto yy1065; + if (yych == 'l') goto yy1066; + } + } +yy1063: +#line 449 "cpp.re" + { BOOST_WAVE_RET(T_FLOATLIT); } +#line 7186 "cpp_re.inc" +yy1064: + yych = *++YYCURSOR; + if (yych <= ',') { + if (yych == '+') goto yy1068; + goto yy1055; + } else { + if (yych <= '-') goto yy1068; + if (yych <= '/') goto yy1055; + if (yych <= '9') goto yy1069; + goto yy1055; + } +yy1065: + yych = *++YYCURSOR; + if (yych == 'L') goto yy1067; + if (yych == 'l') goto yy1067; + goto yy1063; +yy1066: + yych = *++YYCURSOR; + if (yych == 'F') goto yy1067; + if (yych != 'f') goto yy1063; +yy1067: + yych = *++YYCURSOR; + goto yy1063; +yy1068: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1055; + if (yych >= ':') goto yy1055; +yy1069: + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= 'K') { + if (yych <= '9') { + if (yych <= '/') goto yy1063; + goto yy1069; + } else { + if (yych == 'F') goto yy1065; + goto yy1063; + } + } else { + if (yych <= 'f') { + if (yych <= 'L') goto yy1066; + if (yych <= 'e') goto yy1063; + goto yy1065; + } else { + if (yych == 'l') goto yy1066; + goto yy1063; + } + } +yy1071: + yych = *++YYCURSOR; + if (yych <= ',') { + if (yych != '+') goto yy1055; + } else { + if (yych <= '-') goto yy1072; + if (yych <= '/') goto yy1055; + if (yych <= '9') goto yy1073; + goto yy1055; + } +yy1072: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1055; + if (yych >= ':') goto yy1055; +yy1073: + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= 'K') { + if (yych <= '9') { + if (yych <= '/') goto yy1063; + goto yy1073; + } else { + if (yych == 'F') goto yy1065; + goto yy1063; + } + } else { + if (yych <= 'f') { + if (yych <= 'L') goto yy1066; + if (yych <= 'e') goto yy1063; + goto yy1065; + } else { + if (yych == 'l') goto yy1066; + goto yy1063; + } + } +yy1075: + yyaccept = 0; + YYMARKER = ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy1075; + } + if (yych <= '9') { + if (yych == '.') goto yy1061; + if (yych <= '/') goto yy1057; + goto yy1078; + } else { + if (yych <= 'E') { + if (yych <= 'D') goto yy1057; + goto yy1071; + } else { + if (yych == 'e') goto yy1071; + goto yy1057; + } + } +yy1077: + yych = *++YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1080; + } + goto yy1055; +yy1078: + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych == '.') goto yy1061; + if (yych <= '/') goto yy1055; + goto yy1078; + } else { + if (yych <= 'E') { + if (yych <= 'D') goto yy1055; + goto yy1071; + } else { + if (yych == 'e') goto yy1071; + goto yy1055; + } + } +yy1080: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1080; + } + goto yy1057; +} +#line 452 "cpp.re" + + } +} + +/* this subscanner is called, whenever an Integer was recognized */ +integer_suffix: +{ + if (s->enable_ms_extensions) { + +#line 7335 "cpp_re.inc" +{ + YYCTYPE yych; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *(YYMARKER = YYCURSOR); + if (yych <= 'h') { + if (yych <= 'L') { + if (yych >= 'L') goto yy1086; + } else { + if (yych == 'U') goto yy1085; + } + } else { + if (yych <= 'l') { + if (yych <= 'i') goto yy1087; + if (yych >= 'l') goto yy1086; + } else { + if (yych == 'u') goto yy1085; + } + } +yy1084: +#line 465 "cpp.re" + { BOOST_WAVE_RET(T_INTLIT); } +#line 7357 "cpp_re.inc" +yy1085: + yych = *++YYCURSOR; + if (yych == 'L') goto yy1094; + if (yych == 'l') goto yy1094; + goto yy1084; +yy1086: + yych = *++YYCURSOR; + if (yych <= 'U') { + if (yych == 'L') goto yy1093; + if (yych <= 'T') goto yy1084; + goto yy1092; + } else { + if (yych <= 'l') { + if (yych <= 'k') goto yy1084; + goto yy1093; + } else { + if (yych == 'u') goto yy1092; + goto yy1084; + } + } +yy1087: + yych = *++YYCURSOR; + if (yych == '6') goto yy1089; +yy1088: + YYCURSOR = YYMARKER; + goto yy1084; +yy1089: + yych = *++YYCURSOR; + if (yych != '4') goto yy1088; +yy1090: + ++YYCURSOR; +yy1091: +#line 462 "cpp.re" + { BOOST_WAVE_RET(T_LONGINTLIT); } +#line 7392 "cpp_re.inc" +yy1092: + yych = *++YYCURSOR; + goto yy1084; +yy1093: + yych = *++YYCURSOR; + if (yych == 'U') goto yy1090; + if (yych == 'u') goto yy1090; + goto yy1091; +yy1094: + ++YYCURSOR; + if ((yych = *YYCURSOR) == 'L') goto yy1090; + if (yych == 'l') goto yy1090; + goto yy1084; +} +#line 466 "cpp.re" + + } + else { + +#line 7412 "cpp_re.inc" +{ + YYCTYPE yych; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yych <= 'U') { + if (yych == 'L') goto yy1099; + if (yych >= 'U') goto yy1098; + } else { + if (yych <= 'l') { + if (yych >= 'l') goto yy1099; + } else { + if (yych == 'u') goto yy1098; + } + } +yy1097: +#line 474 "cpp.re" + { BOOST_WAVE_RET(T_INTLIT); } +#line 7430 "cpp_re.inc" +yy1098: + yych = *++YYCURSOR; + if (yych == 'L') goto yy1104; + if (yych == 'l') goto yy1104; + goto yy1097; +yy1099: + yych = *++YYCURSOR; + if (yych <= 'U') { + if (yych == 'L') goto yy1101; + if (yych <= 'T') goto yy1097; + } else { + if (yych <= 'l') { + if (yych <= 'k') goto yy1097; + goto yy1101; + } else { + if (yych != 'u') goto yy1097; + } + } + yych = *++YYCURSOR; + goto yy1097; +yy1101: + ++YYCURSOR; + if ((yych = *YYCURSOR) == 'U') goto yy1103; + if (yych == 'u') goto yy1103; +yy1102: +#line 471 "cpp.re" + { BOOST_WAVE_RET(T_LONGINTLIT); } +#line 7458 "cpp_re.inc" +yy1103: + yych = *++YYCURSOR; + goto yy1102; +yy1104: + ++YYCURSOR; + if ((yych = *YYCURSOR) == 'L') goto yy1103; + if (yych == 'l') goto yy1103; + goto yy1097; +} +#line 475 "cpp.re" + + } +} + +/* this subscanner is invoked for C++0x extended character literals */ +extcharlit: +{ + +#line 7477 "cpp_re.inc" +{ + YYCTYPE yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((YYLIMIT - YYCURSOR) < 13) YYFILL(13); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x08) goto yy1107; + if (yych <= '\t') goto yy1108; + goto yy1112; + } else { + if (yych <= '\f') goto yy1108; + if (yych <= '\r') goto yy1112; + } + } else { + if (yych <= '>') { + if (yych == '\'') goto yy1112; + goto yy1108; + } else { + if (yych <= '?') goto yy1110; + if (yych == '\\') goto yy1111; + goto yy1108; + } + } +yy1107: + YYCURSOR = YYMARKER; + goto yy1109; +yy1108: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '\'') goto yy1120; +yy1109: +#line 487 "cpp.re" + { BOOST_WAVE_RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); } +#line 7544 "cpp_re.inc" +yy1110: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '\'') goto yy1120; + if (yych == '?') goto yy1135; + goto yy1109; +yy1111: + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1115; + goto yy1109; + } else { + if (yych <= '\'') goto yy1115; + if (yych <= '/') goto yy1109; + goto yy1118; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1116; + goto yy1109; + } else { + if (yych <= 'U') goto yy1114; + if (yych == '\\') goto yy1115; + goto yy1109; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1115; + if (yych <= 'e') goto yy1109; + goto yy1115; + } else { + if (yych == 'n') goto yy1115; + if (yych <= 'q') goto yy1109; + goto yy1115; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1109; + if (yych <= 't') goto yy1115; + goto yy1113; + } else { + if (yych <= 'v') goto yy1115; + if (yych == 'x') goto yy1117; + goto yy1109; + } + } + } +yy1112: + yych = *++YYCURSOR; + goto yy1109; +yy1113: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych <= '9') goto yy1132; + goto yy1107; + } else { + if (yych <= 'F') goto yy1132; + if (yych <= '`') goto yy1107; + if (yych <= 'f') goto yy1132; + goto yy1107; + } +yy1114: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych <= '9') goto yy1125; + goto yy1107; + } else { + if (yych <= 'F') goto yy1125; + if (yych <= '`') goto yy1107; + if (yych <= 'f') goto yy1125; + goto yy1107; + } +yy1115: + yych = *++YYCURSOR; + if (yych == '\'') goto yy1120; + goto yy1107; +yy1116: + yych = *++YYCURSOR; + if (yych == '\'') goto yy1120; + if (yych == '?') goto yy1124; + goto yy1107; +yy1117: + yych = *++YYCURSOR; + if (yych == '\'') goto yy1107; + goto yy1123; +yy1118: + yych = *++YYCURSOR; + if (yych == '\'') goto yy1120; + if (yych <= '/') goto yy1107; + if (yych >= '8') goto yy1107; + yych = *++YYCURSOR; + if (yych == '\'') goto yy1120; + if (yych <= '/') goto yy1107; + if (yych <= '7') goto yy1115; + goto yy1107; +yy1120: + ++YYCURSOR; +#line 484 "cpp.re" + { BOOST_WAVE_RET(T_CHARLIT); } +#line 7649 "cpp_re.inc" +yy1122: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy1123: + if (yybm[0+yych] & 128) { + goto yy1122; + } + if (yych == '\'') goto yy1120; + goto yy1107; +yy1124: + yych = *++YYCURSOR; + if (yych == '/') goto yy1115; + goto yy1107; +yy1125: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1126; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1126: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1127; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1127: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1128; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1128: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1129; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1129: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1130; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1130: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1131; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1131: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych <= '9') goto yy1115; + goto yy1107; + } else { + if (yych <= 'F') goto yy1115; + if (yych <= '`') goto yy1107; + if (yych <= 'f') goto yy1115; + goto yy1107; + } +yy1132: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1133; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1133: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1134; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1134: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych <= '9') goto yy1115; + goto yy1107; + } else { + if (yych <= 'F') goto yy1115; + if (yych <= '`') goto yy1107; + if (yych <= 'f') goto yy1115; + goto yy1107; + } +yy1135: + yych = *++YYCURSOR; + if (yych != '/') goto yy1107; + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1115; + goto yy1107; + } else { + if (yych <= '\'') goto yy1115; + if (yych <= '/') goto yy1107; + goto yy1118; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1116; + goto yy1107; + } else { + if (yych <= 'U') goto yy1114; + if (yych == '\\') goto yy1115; + goto yy1107; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1115; + if (yych <= 'e') goto yy1107; + goto yy1115; + } else { + if (yych == 'n') goto yy1115; + if (yych <= 'q') goto yy1107; + goto yy1115; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1107; + if (yych <= 't') goto yy1115; + goto yy1113; + } else { + if (yych <= 'v') goto yy1115; + if (yych == 'x') goto yy1117; + goto yy1107; + } + } + } +} +#line 488 "cpp.re" + +} + +/* this subscanner is invoked for C++0x extended character string literals */ +extstringlit: +{ + +#line 7824 "cpp_re.inc" +{ + YYCTYPE yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 16, 0, 16, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 16, 0, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 144, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 16, 16, 16, 16, 16, 32, + 16, 144, 144, 144, 144, 144, 144, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 64, 16, 16, 16, + 16, 144, 144, 144, 144, 144, 144, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x08) goto yy1139; + if (yych <= '\t') goto yy1140; + goto yy1146; + } else { + if (yych <= '\f') goto yy1140; + if (yych <= '\r') goto yy1146; + } + } else { + if (yych <= '>') { + if (yych == '"') goto yy1144; + goto yy1140; + } else { + if (yych <= '?') goto yy1142; + if (yych == '\\') goto yy1143; + goto yy1140; + } + } +yy1139: + YYCURSOR = YYMARKER; + if (yyaccept <= 0) { + goto yy1141; + } else { + goto yy1145; + } +yy1140: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\n') { + if (yych == '\t') goto yy1150; + } else { + if (yych <= '\f') goto yy1150; + if (yych >= ' ') goto yy1150; + } +yy1141: +#line 499 "cpp.re" + { BOOST_WAVE_RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); } +#line 7902 "cpp_re.inc" +yy1142: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy1158; + } + if (yych <= '\n') { + if (yych == '\t') goto yy1150; + goto yy1141; + } else { + if (yych <= '\f') goto yy1150; + if (yych <= 0x1F) goto yy1141; + goto yy1150; + } +yy1143: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1149; + goto yy1141; + } else { + if (yych <= '\'') goto yy1149; + if (yych <= '/') goto yy1141; + goto yy1153; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1151; + goto yy1141; + } else { + if (yych <= 'U') goto yy1148; + if (yych == '\\') goto yy1149; + goto yy1141; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1149; + if (yych <= 'e') goto yy1141; + goto yy1149; + } else { + if (yych == 'n') goto yy1149; + if (yych <= 'q') goto yy1141; + goto yy1149; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1141; + if (yych <= 't') goto yy1149; + goto yy1147; + } else { + if (yych <= 'v') goto yy1149; + if (yych == 'x') goto yy1152; + goto yy1141; + } + } + } +yy1144: + ++YYCURSOR; +yy1145: +#line 496 "cpp.re" + { BOOST_WAVE_RET(T_STRINGLIT); } +#line 7968 "cpp_re.inc" +yy1146: + yych = *++YYCURSOR; + goto yy1141; +yy1147: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych <= '9') goto yy1187; + goto yy1139; + } else { + if (yych <= 'F') goto yy1187; + if (yych <= '`') goto yy1139; + if (yych <= 'f') goto yy1187; + goto yy1139; + } +yy1148: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych <= '9') goto yy1180; + goto yy1139; + } else { + if (yych <= 'F') goto yy1180; + if (yych <= '`') goto yy1139; + if (yych <= 'f') goto yy1180; + goto yy1139; + } +yy1149: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy1150: + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1151: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1179; + goto yy1157; +yy1152: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1166; + } + goto yy1139; +yy1153: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '"') { + if (yych <= '\n') { + if (yych == '\t') goto yy1149; + goto yy1139; + } else { + if (yych <= '\f') goto yy1149; + if (yych <= 0x1F) goto yy1139; + if (yych <= '!') goto yy1149; + goto yy1155; + } + } else { + if (yych <= '>') { + if (yych <= '/') goto yy1149; + if (yych >= '8') goto yy1149; + } else { + if (yych <= '?') goto yy1156; + if (yych == '\\') goto yy1157; + goto yy1149; + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1155: + yych = *++YYCURSOR; + goto yy1145; +yy1156: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1158; +yy1157: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1149; + goto yy1139; + } else { + if (yych <= '\'') goto yy1149; + if (yych <= '/') goto yy1139; + goto yy1153; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1151; + goto yy1139; + } else { + if (yych <= 'U') goto yy1148; + if (yych == '\\') goto yy1149; + goto yy1139; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1149; + if (yych <= 'e') goto yy1139; + goto yy1149; + } else { + if (yych == 'n') goto yy1149; + if (yych <= 'q') goto yy1139; + goto yy1149; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1139; + if (yych <= 't') goto yy1149; + goto yy1147; + } else { + if (yych <= 'v') goto yy1149; + if (yych == 'x') goto yy1152; + goto yy1139; + } + } + } +yy1158: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy1158; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy1149; + goto yy1139; + } else { + if (yych <= '\f') goto yy1149; + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } + } else { + if (yych <= '/') { + if (yych <= '"') goto yy1155; + if (yych <= '.') goto yy1149; + } else { + if (yych == '\\') goto yy1157; + goto yy1149; + } + } +yy1160: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy1160; + } + if (yych <= '7') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1164; + if (yych <= '/') goto yy1149; + goto yy1153; + } + } + } else { + if (yych <= 'U') { + if (yych == '?') goto yy1165; + if (yych <= 'T') goto yy1149; + goto yy1163; + } else { + if (yych <= 'u') { + if (yych <= 't') goto yy1149; + } else { + if (yych == 'x') goto yy1166; + goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + goto yy1176; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + goto yy1176; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych <= 'f') goto yy1176; + goto yy1149; + } + } + } +yy1163: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + goto yy1169; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + goto yy1169; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych <= 'f') goto yy1169; + goto yy1149; + } + } + } +yy1164: + yyaccept = 1; + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1145; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1165: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1168; + goto yy1157; +yy1166: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1166; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy1149; + goto yy1139; + } else { + if (yych <= '\f') goto yy1149; + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } + } else { + if (yych <= '?') { + if (yych <= '"') goto yy1155; + if (yych <= '>') goto yy1149; + goto yy1156; + } else { + if (yych == '\\') goto yy1157; + goto yy1149; + } + } +yy1168: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy1158; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy1149; + goto yy1139; + } else { + if (yych <= '\f') goto yy1149; + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } + } else { + if (yych <= '/') { + if (yych <= '"') goto yy1155; + if (yych <= '.') goto yy1149; + goto yy1160; + } else { + if (yych == '\\') goto yy1157; + goto yy1149; + } + } +yy1169: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1176: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1179: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1158; + goto yy1157; +yy1180: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1181; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1181: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1182; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1182: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1183; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1183: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1184; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1184: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1185; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1185: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1186; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1186: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych <= '9') goto yy1149; + goto yy1139; + } else { + if (yych <= 'F') goto yy1149; + if (yych <= '`') goto yy1139; + if (yych <= 'f') goto yy1149; + goto yy1139; + } +yy1187: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1188; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1188: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1189; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1189: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych <= '9') goto yy1149; + goto yy1139; + } else { + if (yych <= 'F') goto yy1149; + if (yych <= '`') goto yy1139; + if (yych <= 'f') goto yy1149; + goto yy1139; + } +} +#line 500 "cpp.re" + +} + +extrawstringlit: +{ + +#line 8743 "cpp_re.inc" +{ + YYCTYPE yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((YYLIMIT - YYCURSOR) < 12) YYFILL(12); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x08) goto yy1192; + if (yych <= '\t') goto yy1193; + goto yy1197; + } else { + if (yych <= '\f') goto yy1193; + if (yych <= '\r') goto yy1199; + } + } else { + if (yych <= '>') { + if (yych == '"') goto yy1200; + goto yy1193; + } else { + if (yych <= '?') goto yy1195; + if (yych == '\\') goto yy1196; + goto yy1193; + } + } +yy1192: + YYCURSOR = YYMARKER; + goto yy1194; +yy1193: + ++YYCURSOR; +yy1194: +#line 507 "cpp.re" + { + goto extrawstringlit; + } +#line 8811 "cpp_re.inc" +yy1195: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '?') goto yy1221; + goto yy1194; +yy1196: + yych = *++YYCURSOR; + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1193; + goto yy1192; + } else { + if (yych <= '\'') goto yy1193; + if (yych <= '/') goto yy1192; + goto yy1206; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1204; + goto yy1192; + } else { + if (yych <= 'U') goto yy1203; + if (yych == '\\') goto yy1193; + goto yy1192; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1193; + if (yych <= 'e') goto yy1192; + goto yy1193; + } else { + if (yych == 'n') goto yy1193; + if (yych <= 'q') goto yy1192; + goto yy1193; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1192; + if (yych <= 't') goto yy1193; + goto yy1202; + } else { + if (yych <= 'v') goto yy1193; + if (yych == 'x') goto yy1205; + goto yy1192; + } + } + } +yy1197: + ++YYCURSOR; +yy1198: +#line 512 "cpp.re" + { + s->line += count_backslash_newlines(s, cursor) +1; + cursor.column = 1; + goto extrawstringlit; + } +#line 8870 "cpp_re.inc" +yy1199: + yych = *++YYCURSOR; + if (yych == '\n') goto yy1197; + goto yy1198; +yy1200: + ++YYCURSOR; +#line 518 "cpp.re" + { BOOST_WAVE_RET(T_RAWSTRINGLIT); } +#line 8879 "cpp_re.inc" +yy1202: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych <= '9') goto yy1218; + goto yy1192; + } else { + if (yych <= 'F') goto yy1218; + if (yych <= '`') goto yy1192; + if (yych <= 'f') goto yy1218; + goto yy1192; + } +yy1203: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych <= '9') goto yy1211; + goto yy1192; + } else { + if (yych <= 'F') goto yy1211; + if (yych <= '`') goto yy1192; + if (yych <= 'f') goto yy1211; + goto yy1192; + } +yy1204: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '?') goto yy1210; + goto yy1194; +yy1205: + yych = *++YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1208; + } + goto yy1192; +yy1206: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1194; + if (yych >= '8') goto yy1194; + yych = *++YYCURSOR; + if (yych <= '/') goto yy1194; + if (yych <= '7') goto yy1193; + goto yy1194; +yy1208: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1208; + } + goto yy1194; +yy1210: + yych = *++YYCURSOR; + if (yych == '/') goto yy1193; + goto yy1192; +yy1211: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1212; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1212: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1213; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1213: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1214; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1214: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1215; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1215: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1216; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1216: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1217; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1217: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych <= '9') goto yy1193; + goto yy1192; + } else { + if (yych <= 'F') goto yy1193; + if (yych <= '`') goto yy1192; + if (yych <= 'f') goto yy1193; + goto yy1192; + } +yy1218: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1219; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1219: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1220; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1220: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych <= '9') goto yy1193; + goto yy1192; + } else { + if (yych <= 'F') goto yy1193; + if (yych <= '`') goto yy1192; + if (yych <= 'f') goto yy1193; + goto yy1192; + } +yy1221: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '/') goto yy1196; + goto yy1192; +} +#line 519 "cpp.re" + +} diff --git a/extern/shiny/Preprocessor/instantiate_cpp_exprgrammar.cpp b/extern/shiny/Preprocessor/instantiate_cpp_exprgrammar.cpp new file mode 100644 index 0000000000..7318c29fa4 --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_cpp_exprgrammar.cpp @@ -0,0 +1,52 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include +#include + +#include +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the expression_grammar_gen template with the +// correct lexer iterator type. This instantiates the corresponding parse +// function, which in turn instantiates the expression_grammar object (see +// wave/grammars/cpp_expression_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use your own token type the following line must be adjusted +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +template struct boost::wave::grammars::expression_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_cpp_grammar.cpp b/extern/shiny/Preprocessor/instantiate_cpp_grammar.cpp new file mode 100644 index 0000000000..89cc3d7f36 --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_cpp_grammar.cpp @@ -0,0 +1,56 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include +#include + +#include +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the cpp_grammar_gen template with the correct +// token type. This instantiates the corresponding pt_parse function, which +// in turn instantiates the cpp_grammar object +// (see wave/grammars/cpp_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use your own token type the following line must be adjusted +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +typedef boost::wave::cpplexer::lex_iterator lexer_type; +typedef std::list > + token_sequence_type; + +template struct boost::wave::grammars::cpp_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_cpp_literalgrs.cpp b/extern/shiny/Preprocessor/instantiate_cpp_literalgrs.cpp new file mode 100644 index 0000000000..4fbfb87f22 --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_cpp_literalgrs.cpp @@ -0,0 +1,56 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include +#include +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the intlit_grammar_gen and chlit_grammar_gen +// templates with the correct token type. This instantiates the corresponding +// parse function, which in turn instantiates the corresponding parser object. +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +template struct boost::wave::grammars::intlit_grammar_gen; +#if BOOST_WAVE_WCHAR_T_SIGNEDNESS == BOOST_WAVE_WCHAR_T_AUTOSELECT || \ + BOOST_WAVE_WCHAR_T_SIGNEDNESS == BOOST_WAVE_WCHAR_T_FORCE_SIGNED +template struct boost::wave::grammars::chlit_grammar_gen; +#endif +template struct boost::wave::grammars::chlit_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_defined_grammar.cpp b/extern/shiny/Preprocessor/instantiate_defined_grammar.cpp new file mode 100644 index 0000000000..b7afe3f1ef --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_defined_grammar.cpp @@ -0,0 +1,52 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the defined_grammar_gen template +// with the correct token type. This instantiates the corresponding parse +// function, which in turn instantiates the defined_grammar +// object (see wave/grammars/cpp_defined_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use your own token type the following line must be adjusted +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +typedef boost::wave::cpplexer::lex_iterator lexer_type; +template struct boost::wave::grammars::defined_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_predef_macros.cpp b/extern/shiny/Preprocessor/instantiate_predef_macros.cpp new file mode 100644 index 0000000000..758ad9734a --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_predef_macros.cpp @@ -0,0 +1,52 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the predefined_macros_grammar_gen template +// with the correct token type. This instantiates the corresponding pt_parse +// function, which in turn instantiates the cpp_predefined_macros_grammar +// object (see wave/grammars/cpp_predef_macros_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use your own token type the following line must be adjusted +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +typedef boost::wave::cpplexer::lex_iterator lexer_type; +template struct boost::wave::grammars::predefined_macros_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_re2c_lexer.cpp b/extern/shiny/Preprocessor/instantiate_re2c_lexer.cpp new file mode 100644 index 0000000000..cd1b8898ff --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_re2c_lexer.cpp @@ -0,0 +1,65 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Explicit instantiation of the lex_functor generation function + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include // configuration data + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// This instantiates the correct 'new_lexer' function, which generates the +// C++ lexer used in this sample. You will have to instantiate the +// new_lexer_gen<> template with the same iterator type, as you have used for +// instantiating the boost::wave::context<> object. +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the first +// parameter supplied while instantiating the boost::wave::context<> template +// (see the file cpp.cpp). +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use another iterator type for the underlying input stream +// a corresponding explicit template instantiation needs to be added below +template struct boost::wave::cpplexer::new_lexer_gen< + BOOST_WAVE_STRINGTYPE::iterator>; +template struct boost::wave::cpplexer::new_lexer_gen< + BOOST_WAVE_STRINGTYPE::const_iterator>; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/extern/shiny/Preprocessor/instantiate_re2c_lexer_str.cpp b/extern/shiny/Preprocessor/instantiate_re2c_lexer_str.cpp new file mode 100644 index 0000000000..138ed6c3bb --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_re2c_lexer_str.cpp @@ -0,0 +1,64 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Explicit instantiation of the lex_functor generation function + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include // configuration data + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// If you've used another iterator type as std::string::iterator, you have to +// instantiate the new_lexer_gen<> template for this iterator type too. +// The reason is, that the library internally uses the new_lexer_gen<> +// template with a std::string::iterator. (You just have to undefine the +// following line.) +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the first +// parameter supplied while instantiating the boost::wave::context<> template +// (see the file cpp.cpp). +// +/////////////////////////////////////////////////////////////////////////////// + +#if !defined(BOOST_WAVE_STRINGTYPE_USE_STDSTRING) +template struct boost::wave::cpplexer::new_lexer_gen; +template struct boost::wave::cpplexer::new_lexer_gen; +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/extern/shiny/Preprocessor/token_ids.cpp b/extern/shiny/Preprocessor/token_ids.cpp new file mode 100644 index 0000000000..35e7725b43 --- /dev/null +++ b/extern/shiny/Preprocessor/token_ids.cpp @@ -0,0 +1,447 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + The definition of a default set of token identifiers and related + functions. + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include + +#include +#include +#include + +#include +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +/////////////////////////////////////////////////////////////////////////////// +// return a token name +BOOST_WAVE_STRINGTYPE +get_token_name(token_id tokid) +{ +// Table of token names +// +// Please note that the sequence of token names must match the sequence of +// token id's defined in then enum token_id above. +static char const *tok_names[] = { + /* 256 */ "AND", + /* 257 */ "ANDAND", + /* 258 */ "ASSIGN", + /* 259 */ "ANDASSIGN", + /* 260 */ "OR", + /* 261 */ "ORASSIGN", + /* 262 */ "XOR", + /* 263 */ "XORASSIGN", + /* 264 */ "COMMA", + /* 265 */ "COLON", + /* 266 */ "DIVIDE", + /* 267 */ "DIVIDEASSIGN", + /* 268 */ "DOT", + /* 269 */ "DOTSTAR", + /* 270 */ "ELLIPSIS", + /* 271 */ "EQUAL", + /* 272 */ "GREATER", + /* 273 */ "GREATEREQUAL", + /* 274 */ "LEFTBRACE", + /* 275 */ "LESS", + /* 276 */ "LESSEQUAL", + /* 277 */ "LEFTPAREN", + /* 278 */ "LEFTBRACKET", + /* 279 */ "MINUS", + /* 280 */ "MINUSASSIGN", + /* 281 */ "MINUSMINUS", + /* 282 */ "PERCENT", + /* 283 */ "PERCENTASSIGN", + /* 284 */ "NOT", + /* 285 */ "NOTEQUAL", + /* 286 */ "OROR", + /* 287 */ "PLUS", + /* 288 */ "PLUSASSIGN", + /* 289 */ "PLUSPLUS", + /* 290 */ "ARROW", + /* 291 */ "ARROWSTAR", + /* 292 */ "QUESTION_MARK", + /* 293 */ "RIGHTBRACE", + /* 294 */ "RIGHTPAREN", + /* 295 */ "RIGHTBRACKET", + /* 296 */ "COLON_COLON", + /* 297 */ "SEMICOLON", + /* 298 */ "SHIFTLEFT", + /* 299 */ "SHIFTLEFTASSIGN", + /* 300 */ "SHIFTRIGHT", + /* 301 */ "SHIFTRIGHTASSIGN", + /* 302 */ "STAR", + /* 303 */ "COMPL", + /* 304 */ "STARASSIGN", + /* 305 */ "ASM", + /* 306 */ "AUTO", + /* 307 */ "BOOL", + /* 308 */ "FALSE", + /* 309 */ "TRUE", + /* 310 */ "BREAK", + /* 311 */ "CASE", + /* 312 */ "CATCH", + /* 313 */ "CHAR", + /* 314 */ "CLASS", + /* 315 */ "CONST", + /* 316 */ "CONSTCAST", + /* 317 */ "CONTINUE", + /* 318 */ "DEFAULT", + /* 319 */ "DELETE", + /* 320 */ "DO", + /* 321 */ "DOUBLE", + /* 322 */ "DYNAMICCAST", + /* 323 */ "ELSE", + /* 324 */ "ENUM", + /* 325 */ "EXPLICIT", + /* 326 */ "EXPORT", + /* 327 */ "EXTERN", + /* 328 */ "FLOAT", + /* 329 */ "FOR", + /* 330 */ "FRIEND", + /* 331 */ "GOTO", + /* 332 */ "IF", + /* 333 */ "INLINE", + /* 334 */ "INT", + /* 335 */ "LONG", + /* 336 */ "MUTABLE", + /* 337 */ "NAMESPACE", + /* 338 */ "NEW", + /* 339 */ "OPERATOR", + /* 340 */ "PRIVATE", + /* 341 */ "PROTECTED", + /* 342 */ "PUBLIC", + /* 343 */ "REGISTER", + /* 344 */ "REINTERPRETCAST", + /* 345 */ "RETURN", + /* 346 */ "SHORT", + /* 347 */ "SIGNED", + /* 348 */ "SIZEOF", + /* 349 */ "STATIC", + /* 350 */ "STATICCAST", + /* 351 */ "STRUCT", + /* 352 */ "SWITCH", + /* 353 */ "TEMPLATE", + /* 354 */ "THIS", + /* 355 */ "THROW", + /* 356 */ "TRY", + /* 357 */ "TYPEDEF", + /* 358 */ "TYPEID", + /* 359 */ "TYPENAME", + /* 360 */ "UNION", + /* 361 */ "UNSIGNED", + /* 362 */ "USING", + /* 363 */ "VIRTUAL", + /* 364 */ "VOID", + /* 365 */ "VOLATILE", + /* 366 */ "WCHART", + /* 367 */ "WHILE", + /* 368 */ "PP_DEFINE", + /* 369 */ "PP_IF", + /* 370 */ "PP_IFDEF", + /* 371 */ "PP_IFNDEF", + /* 372 */ "PP_ELSE", + /* 373 */ "PP_ELIF", + /* 374 */ "PP_ENDIF", + /* 375 */ "PP_ERROR", + /* 376 */ "PP_LINE", + /* 377 */ "PP_PRAGMA", + /* 378 */ "PP_UNDEF", + /* 379 */ "PP_WARNING", + /* 380 */ "IDENTIFIER", + /* 381 */ "OCTALINT", + /* 382 */ "DECIMALINT", + /* 383 */ "HEXAINT", + /* 384 */ "INTLIT", + /* 385 */ "LONGINTLIT", + /* 386 */ "FLOATLIT", + /* 387 */ "CCOMMENT", + /* 388 */ "CPPCOMMENT", + /* 389 */ "CHARLIT", + /* 390 */ "STRINGLIT", + /* 391 */ "CONTLINE", + /* 392 */ "SPACE", + /* 393 */ "SPACE2", + /* 394 */ "NEWLINE", + /* 395 */ "POUND_POUND", + /* 396 */ "POUND", + /* 397 */ "ANY", + /* 398 */ "PP_INCLUDE", + /* 399 */ "PP_QHEADER", + /* 400 */ "PP_HHEADER", + /* 401 */ "EOF", + /* 402 */ "EOI", + /* 403 */ "PP_NUMBER", + + // MS extensions + /* 404 */ "MSEXT_INT8", + /* 405 */ "MSEXT_INT16", + /* 406 */ "MSEXT_INT32", + /* 407 */ "MSEXT_INT64", + /* 408 */ "MSEXT_BASED", + /* 409 */ "MSEXT_DECLSPEC", + /* 410 */ "MSEXT_CDECL", + /* 411 */ "MSEXT_FASTCALL", + /* 412 */ "MSEXT_STDCALL", + /* 413 */ "MSEXT_TRY", + /* 414 */ "MSEXT_EXCEPT", + /* 415 */ "MSEXT_FINALLY", + /* 416 */ "MSEXT_LEAVE", + /* 417 */ "MSEXT_INLINE", + /* 418 */ "MSEXT_ASM", + /* 419 */ "MSEXT_REGION", + /* 420 */ "MSEXT_ENDREGION", + + /* 421 */ "IMPORT", + + /* 422 */ "ALIGNAS", + /* 423 */ "ALIGNOF", + /* 424 */ "CHAR16_T", + /* 425 */ "CHAR32_T", + /* 426 */ "CONSTEXPR", + /* 427 */ "DECLTYPE", + /* 428 */ "NOEXCEPT", + /* 429 */ "NULLPTR", + /* 430 */ "STATIC_ASSERT", + /* 431 */ "THREADLOCAL", + /* 432 */ "RAWSTRINGLIT", + }; + + // make sure, I have not forgotten any commas (as I did more than once) + BOOST_STATIC_ASSERT( + sizeof(tok_names)/sizeof(tok_names[0]) == T_LAST_TOKEN-T_FIRST_TOKEN + ); + + unsigned int id = BASEID_FROM_TOKEN(tokid)-T_FIRST_TOKEN; + return (id < T_LAST_TOKEN-T_FIRST_TOKEN) ? tok_names[id] : ""; +} + +/////////////////////////////////////////////////////////////////////////////// +// return a token name +char const * +get_token_value(token_id tokid) +{ +// Table of token values +// +// Please note that the sequence of token names must match the sequence of +// token id's defined in then enum token_id above. +static char const *tok_values[] = { + /* 256 */ "&", + /* 257 */ "&&", + /* 258 */ "=", + /* 259 */ "&=", + /* 260 */ "|", + /* 261 */ "|=", + /* 262 */ "^", + /* 263 */ "^=", + /* 264 */ ",", + /* 265 */ ":", + /* 266 */ "/", + /* 267 */ "/=", + /* 268 */ ".", + /* 269 */ ".*", + /* 270 */ "...", + /* 271 */ "==", + /* 272 */ ">", + /* 273 */ ">=", + /* 274 */ "{", + /* 275 */ "<", + /* 276 */ "<=", + /* 277 */ "(", + /* 278 */ "[", + /* 279 */ "-", + /* 280 */ "-=", + /* 281 */ "--", + /* 282 */ "%", + /* 283 */ "%=", + /* 284 */ "!", + /* 285 */ "!=", + /* 286 */ "||", + /* 287 */ "+", + /* 288 */ "+=", + /* 289 */ "++", + /* 290 */ "->", + /* 291 */ "->*", + /* 292 */ "?", + /* 293 */ "}", + /* 294 */ ")", + /* 295 */ "]", + /* 296 */ "::", + /* 297 */ ";", + /* 298 */ "<<", + /* 299 */ "<<=", + /* 300 */ ">>", + /* 301 */ ">>=", + /* 302 */ "*", + /* 303 */ "~", + /* 304 */ "*=", + /* 305 */ "asm", + /* 306 */ "auto", + /* 307 */ "bool", + /* 308 */ "false", + /* 309 */ "true", + /* 310 */ "break", + /* 311 */ "case", + /* 312 */ "catch", + /* 313 */ "char", + /* 314 */ "class", + /* 315 */ "const", + /* 316 */ "const_cast", + /* 317 */ "continue", + /* 318 */ "default", + /* 319 */ "delete", + /* 320 */ "do", + /* 321 */ "double", + /* 322 */ "dynamic_cast", + /* 323 */ "else", + /* 324 */ "enum", + /* 325 */ "explicit", + /* 326 */ "export", + /* 327 */ "extern", + /* 328 */ "float", + /* 329 */ "for", + /* 330 */ "friend", + /* 331 */ "goto", + /* 332 */ "if", + /* 333 */ "inline", + /* 334 */ "int", + /* 335 */ "long", + /* 336 */ "mutable", + /* 337 */ "namespace", + /* 338 */ "new", + /* 339 */ "operator", + /* 340 */ "private", + /* 341 */ "protected", + /* 342 */ "public", + /* 343 */ "register", + /* 344 */ "reinterpret_cast", + /* 345 */ "return", + /* 346 */ "short", + /* 347 */ "signed", + /* 348 */ "sizeof", + /* 349 */ "static", + /* 350 */ "static_cast", + /* 351 */ "struct", + /* 352 */ "switch", + /* 353 */ "template", + /* 354 */ "this", + /* 355 */ "throw", + /* 356 */ "try", + /* 357 */ "typedef", + /* 358 */ "typeid", + /* 359 */ "typename", + /* 360 */ "union", + /* 361 */ "unsigned", + /* 362 */ "using", + /* 363 */ "virtual", + /* 364 */ "void", + /* 365 */ "volatile", + /* 366 */ "wchar_t", + /* 367 */ "while", + /* 368 */ "#define", + /* 369 */ "#if", + /* 370 */ "#ifdef", + /* 371 */ "#ifndef", + /* 372 */ "#else", + /* 373 */ "#elif", + /* 374 */ "#endif", + /* 375 */ "#error", + /* 376 */ "#line", + /* 377 */ "#pragma", + /* 378 */ "#undef", + /* 379 */ "#warning", + /* 380 */ "", // identifier + /* 381 */ "", // octalint + /* 382 */ "", // decimalint + /* 383 */ "", // hexlit + /* 384 */ "", // intlit + /* 385 */ "", // longintlit + /* 386 */ "", // floatlit + /* 387 */ "", // ccomment + /* 388 */ "", // cppcomment + /* 389 */ "", // charlit + /* 390 */ "", // stringlit + /* 391 */ "", // contline + /* 392 */ "", // space + /* 393 */ "", // space2 + /* 394 */ "\n", + /* 395 */ "##", + /* 396 */ "#", + /* 397 */ "", // any + /* 398 */ "#include", + /* 399 */ "#include", + /* 400 */ "#include", + /* 401 */ "", // eof + /* 402 */ "", // eoi + /* 403 */ "", // pp-number + + // MS extensions + /* 404 */ "__int8", + /* 405 */ "__int16", + /* 406 */ "__int32", + /* 407 */ "__int64", + /* 408 */ "__based", + /* 409 */ "__declspec", + /* 410 */ "__cdecl", + /* 411 */ "__fastcall", + /* 412 */ "__stdcall", + /* 413 */ "__try", + /* 414 */ "__except", + /* 415 */ "__finally", + /* 416 */ "__leave", + /* 417 */ "__inline", + /* 418 */ "__asm", + /* 419 */ "#region", + /* 420 */ "#endregion", + + /* 421 */ "import", + + /* 422 */ "alignas", + /* 423 */ "alignof", + /* 424 */ "char16_t", + /* 425 */ "char32_t", + /* 426 */ "constexpr", + /* 427 */ "decltype", + /* 428 */ "noexcept", + /* 429 */ "nullptr", + /* 430 */ "static_assert", + /* 431 */ "threadlocal", + /* 432 */ "", // extrawstringlit + }; + + // make sure, I have not forgotten any commas (as I did more than once) + BOOST_STATIC_ASSERT( + sizeof(tok_values)/sizeof(tok_values[0]) == T_LAST_TOKEN-T_FIRST_TOKEN + ); + + unsigned int id = BASEID_FROM_TOKEN(tokid)-T_FIRST_TOKEN; + return (id < T_LAST_TOKEN-T_FIRST_TOKEN) ? tok_values[id] : ""; +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + + diff --git a/extern/shiny/Readme.txt b/extern/shiny/Readme.txt new file mode 100644 index 0000000000..6133219906 --- /dev/null +++ b/extern/shiny/Readme.txt @@ -0,0 +1,33 @@ +shiny - a shader and material management library for OGRE + +FEATURES + +- High-level layer on top of OGRE's material system. It allows you to generate multiple techniques for all your materials from a set of high-level per-material properties. + +- Several available Macros in shader source files. Just a few examples of the possibilities: binding OGRE auto constants, binding uniforms to material properties, foreach loops (repeat shader source a given number of times), retrieving per-material properties in an #if condition, automatic packing for vertex to fragment passthroughs. These macros allow you to generate even very complex shaders (for example the Ogre::Terrain shader) without assembling them in C++ code. + +- Integrated preprocessor (no, I didn't reinvent the wheel, I used boost::wave which turned out to be an excellent choice) that allows me to blend out macros that shouldn't be in use because e.g. the shader permutation doesn't need this specific feature. + +- User settings integration. They can be set by a C++ interface and retrieved through a macro in shader files. + +- Automatic handling of shader permutations, i.e. shaders are shared between materials in a smart way. + +- An optional "meta-language" (well, actually it's just a small header with some conditional defines) that you may use to compile the same shader source for different target languages. If you don't like it, you can still code in GLSL / CG etc separately. You can also switch between the languages at runtime. + +- On-demand material and shader creation. It uses Ogre's material listener to compile the shaders as soon as they are needed for rendering, and not earlier. + +- Shader changes are fully dynamic and real-time. Changing a user setting will recompile all shaders affected by this setting when they are next needed. + +- Serialization system that extends Ogre's material script system, it uses Ogre's script parser, but also adds some additional properties that are not available in Ogre's material system. + +- A concept called "Configuration" allowing you to create a different set of your shaders, doing the same thing except for some minor differences: the properties that are overridden by the active configuration. Possible uses for this are using simpler shaders (no shadows, no fog etc) when rendering for example realtime reflections or a minimap. You can easily switch between configurations by changing the active Ogre material scheme (for example on a viewport level). + +- Fixed function support. You can globally enable or disable shaders at any time, and for texture units you can specify if they're only needed for the shader-based path (e.g. normal maps) or if they should also be created in the fixed function path. + +LICENSE + +see License.txt + +AUTHOR + +scrawl From b1ffdf855fbab4df838a86e3f310c876261dc000 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Jan 2013 04:48:53 -0800 Subject: [PATCH 0161/1483] Reset the initial state of animated nodes on the skeleton instances This is so the animation specifies node keyframe data based on the node's parent. This will also be necessary for applying animations from different skeleton sources, as they can have different binding positions (even native .skeleton resources will need to specify animation data this way). --- apps/openmw/mwrender/animation.cpp | 22 +++++++++++++++++++++- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5a5761faa3..a36155dbed 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,7 +78,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); - mStartPosition = mNonAccumRoot->getPosition(); + mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; asiter = aset->getAnimationStateIterator(); @@ -93,6 +93,26 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } + + // Reset initial state of bones that are animated, so the animation correctly applies. + if(skelinst->getNumAnimations() > 0) + { + Ogre::Animation *anim = skelinst->getAnimation(0); + Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); + while(trackiter.hasMoreElements()) + { + const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); + const Ogre::Node *srcbone = dynamic_cast(srcnode); + if(!srcbone || !skelinst->hasBone(srcbone->getName())) + continue; + + Ogre::Bone *bone = skelinst->getBone(srcbone->getName()); + bone->setOrientation(Ogre::Quaternion::IDENTITY); + bone->setPosition(Ogre::Vector3::ZERO); + bone->setScale(Ogre::Vector3(1.0f)); + bone->setInitialState(); + } + } } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index adc05f7e7f..ce0fb00fcd 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -193,19 +193,16 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? anim->getNodeTrack(bone->getHandle()) : anim->createNodeTrack(bone->getHandle(), bone); - const Ogre::Quaternion &startquat = bone->getInitialOrientation(); - const Ogre::Vector3 &starttrans = bone->getInitialPosition(); - const Ogre::Vector3 &startscale = bone->getInitialScale(); 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; + lastquat = curquat = quatiter->mValue; if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue - starttrans; + lasttrans = curtrans = traniter->mValue; if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + lastscale = curscale = Ogre::Vector3(scaleiter->mValue); float begTime = std::max(kfc->timeStart, startTime); float endTime = std::min(kfc->timeStop, stopTime); bool didlast = false; @@ -235,19 +232,19 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const { lastquat = curquat; if(++quatiter != quatkeys.mKeys.end()) - curquat = startquat.Inverse() * quatiter->mValue; + curquat = quatiter->mValue; } while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) { lasttrans = curtrans; if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue - starttrans; + curtrans = traniter->mValue; } while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) { lastscale = curscale; if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + curscale = Ogre::Vector3(scaleiter->mValue); } Ogre::TransformKeyFrame *kframe; From 5579df30ff260c48861040350c9c8b7d509d6573 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sat, 26 Jan 2013 18:19:04 +0100 Subject: [PATCH 0162/1483] Implemented data/data-local support and added settingshandlers to main.cpp --- apps/launcher/main.cpp | 144 +++++++++++++++++++++++- apps/launcher/settings/gamesettings.cpp | 125 +++++++++++++++++++- apps/launcher/settings/gamesettings.hpp | 43 ++++++- 3 files changed, 300 insertions(+), 12 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 7c4cb5f7e8..3fef62bc65 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,8 +1,22 @@ #include +#include +#include +#include #include +#include +#include +#include +#include #include +#include + +#include + #include "maindialog.hpp" +#include "settings/gamesettings.hpp" +#include "settings/graphicssettings.hpp" + int main(int argc, char *argv[]) { @@ -30,14 +44,136 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); - MainDialog mainWin; + // Create setting file handlers - if (mainWin.setup()) { + Files::ConfigurationManager cfgMgr; + QString userPath = QString::fromStdString(cfgMgr.getUserPath().string()); + QString globalPath = QString::fromStdString(cfgMgr.getGlobalPath().string()); - mainWin.show(); - return app.exec(); + GameSettings gameSettings(cfgMgr); + GraphicsSettings graphicsSettings; + + QStringList paths; + paths.append(userPath + QString("openmw.cfg")); + paths.append(QString("openmw.cfg")); + paths.append(globalPath + QString("openmw.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error opening OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return 0; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + gameSettings.readFile(stream); + } + file.close(); } + if (gameSettings.getDataDirs().isEmpty()) + { + QMessageBox msgBox; + msgBox.setWindowTitle("Error detecting Morrowind installation"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(QObject::tr("
Could not find the Data Files location

\ + The directory containing the data files was not found.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + QString selectedFile; + if (msgBox.clickedButton() == dirSelectButton) { + selectedFile = QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select master file"), + QDir::currentPath(), + QString("Morrowind master file (*.esm)")); + } + + if (selectedFile.isEmpty()) + return 0; // Cancel was clicked; + + qDebug() << selectedFile; + QFileInfo info(selectedFile); + + // Add the new dir to the settings file and to the data dir container + gameSettings.setValue(QString("data"), info.absolutePath()); + gameSettings.addDataDir(info.absolutePath()); + + } + + // On to the graphics settings + qDebug() << userPath; + + QFile localDefault(QString("settings-default.cfg")); + QFile globalDefault(globalPath + QString("settings-default.cfg")); + + if (!localDefault.exists() && !globalDefault.exists()) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error reading OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not find settings-default.cfg

\ + The problem may be due to an incomplete installation of OpenMW.
\ + Reinstalling OpenMW may resolve the problem.")); + msgBox.exec(); + return 0; + } + + paths.clear(); + paths.append(globalPath + QString("settings-default.cfg")); + paths.append(QString("settings-default.cfg")); + + paths.append(userPath + QString("settings.cfg")); + paths.append(QString("settings.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error opening OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return 0; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + graphicsSettings.readFile(stream); + } + file.close(); + } + + + MainDialog mainWin; + mainWin.setup(); + + mainWin.show(); + QCoreApplication::processEvents(); + return app.exec(); + + return 0; } diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 32f03ddbe3..2420c1e6c0 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -1,13 +1,17 @@ #include +#include #include #include #include #include +#include + #include "gamesettings.hpp" -GameSettings::GameSettings() +GameSettings::GameSettings(Files::ConfigurationManager &cfg) + : mCfgMgr(cfg) { } @@ -15,11 +19,124 @@ GameSettings::~GameSettings() { } +void GameSettings::validatePaths() +{ + qDebug() << "validate paths!"; + + if (mSettings.isEmpty()) + return; + + QStringList paths = mSettings.values(QString("data")); + Files::PathContainer dataDirs; + + foreach (const QString &path, paths) { + dataDirs.push_back(Files::PathContainer::value_type(path.toStdString())); + } + + // Parse the data dirs to convert the tokenized paths + mCfgMgr.processPaths(dataDirs); + +// // Replace the existing data paths with valid untokenized ones +// mSettings.remove(QString("data")); + mDataDirs.clear(); + + for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { + QString path = QString::fromStdString(it->string()); + path.remove(QChar('\"')); + + QDir dir(path); + if (dir.exists()) + mDataDirs.append(path); + } + + // Do the same for data-local + QString local = mSettings.value(QString("data-local")); + + if (local.isEmpty()) + return; + + dataDirs.clear(); + dataDirs.push_back(Files::PathContainer::value_type(local.toStdString())); + + mCfgMgr.processPaths(dataDirs); +// mSettings.remove(QString("data-local")); + + if (!dataDirs.empty()) { + QString path = QString::fromStdString(dataDirs.front().string()); + path.remove(QChar('\"')); + + QDir dir(path); + if (dir.exists()) + mDataLocal = path; + } + qDebug() << mSettings; + + +} + +QStringList GameSettings::values(const QString &key, const QStringList &defaultValues) +{ + if (!mSettings.values(key).isEmpty()) + return mSettings.values(key); + return defaultValues; +} + +bool GameSettings::readFile(QTextStream &stream) +{ + QMap cache; + QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); + + while (!stream.atEnd()) { + QString line = stream.readLine().simplified(); + + if (line.isEmpty() || line.startsWith("#")) + continue; + + qDebug() << "line: " << line; + if (keyRe.indexIn(line) != -1) { + + QString key = keyRe.cap(1).simplified(); + QString value = keyRe.cap(2).simplified(); + + qDebug() << "key: " << key; + // There can be multiple data keys + if (key == QLatin1String("data")) { + cache.insertMulti(key, value); + } else { + cache.insert(key, value); + } + } + } + + if (mSettings.isEmpty()) { + mSettings = cache; // This is the first time we read a file + validatePaths(); + return true; + } + + // Replace values from previous settings + QMapIterator i(cache); + while (i.hasNext()) { + i.next(); + + // Don't remove existing data entries + if (i.key() == QLatin1String("data")) + continue; + + if (mSettings.contains(i.key())) + mSettings.remove(i.key()); + } + + // Merge the changed keys with those which didn't + mSettings.unite(cache); + validatePaths(); + qDebug() << mSettings; + return true; +} + bool GameSettings::writeFile(QTextStream &stream) { - QMap settings = SettingsBase::getSettings(); - - QMapIterator i(settings); + QMapIterator i(mSettings); while (i.hasNext()) { i.next(); diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index c81c67d978..717ce6e877 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -1,15 +1,50 @@ #ifndef GAMESETTINGS_HPP #define GAMESETTINGS_HPP -#include "settingsbase.hpp" +#include -class GameSettings : public SettingsBase> +#include + +class QTextStream; +class QStringList; +class QString; + +namespace Files { typedef std::vector PathContainer; + struct ConfigurationManager;} + +class GameSettings { public: - GameSettings(); + GameSettings(Files::ConfigurationManager &cfg); ~GameSettings(); - bool writeFile(QTextStream &stream); + inline QString value(const QString &key, const QString &defaultValue = QString()) + { + return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key); + } + + + inline void setValue(const QString &key, const QString &value) + { + mSettings.insert(key, value); + } + + inline QStringList getDataDirs() { return mDataDirs; } + inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } + inline QString getDataLocal() {return mDataLocal; } + + QStringList values(const QString &key, const QStringList &defaultValues = QStringList()); + bool readFile(QTextStream &stream); + bool writeFile(QTextStream &stream); + +private: + Files::ConfigurationManager &mCfgMgr; + + void validatePaths(); + QMap mSettings; + + QStringList mDataDirs; + QString mDataLocal; }; #endif // GAMESETTINGS_HPP From 7b71b4eb31c53beaa13fd369d3d831b3508810c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Jan 2013 03:03:48 -0800 Subject: [PATCH 0163/1483] Add a missing include --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5d9250ab66..0888a45221 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -16,6 +16,7 @@ #include "player.hpp" #include "manualref.hpp" #include "cellfunctors.hpp" +#include "containerstore.hpp" using namespace Ogre; From 25edba088754aec279b41e25d4b244722cd3d037 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 27 Jan 2013 16:39:51 +0100 Subject: [PATCH 0164/1483] Rewriting the config code of the pages to use the new settings classes --- apps/launcher/CMakeLists.txt | 3 - apps/launcher/datafilespage.cpp | 368 +++++++++++------------------ apps/launcher/datafilespage.hpp | 13 +- apps/launcher/graphicspage.cpp | 94 ++++---- apps/launcher/graphicspage.hpp | 14 +- apps/launcher/main.cpp | 16 +- apps/launcher/maindialog.cpp | 116 +++++---- apps/launcher/maindialog.hpp | 9 +- apps/launcher/utils/filedialog.cpp | 57 ----- apps/launcher/utils/filedialog.hpp | 28 --- 10 files changed, 290 insertions(+), 428 deletions(-) delete mode 100644 apps/launcher/utils/filedialog.cpp delete mode 100644 apps/launcher/utils/filedialog.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 2895b6345f..044a0a0b73 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -12,7 +12,6 @@ set(LAUNCHER settings/gamesettings.cpp settings/graphicssettings.cpp - utils/filedialog.cpp utils/naturalsort.cpp utils/lineedit.cpp utils/profilescombobox.cpp @@ -36,7 +35,6 @@ set(LAUNCHER_HEADER settings/settingsbase.hpp utils/lineedit.hpp - utils/filedialog.hpp utils/naturalsort.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp @@ -55,7 +53,6 @@ set(LAUNCHER_HEADER_MOC model/esm/esmfile.hpp utils/lineedit.hpp - utils/filedialog.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp ) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 6b0539c1dd..e253003940 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -6,8 +6,9 @@ #include "model/datafilesmodel.hpp" #include "model/esm/esmfile.hpp" +#include "settings/gamesettings.hpp" + #include "utils/profilescombobox.hpp" -#include "utils/filedialog.hpp" #include "utils/lineedit.hpp" #include "utils/naturalsort.hpp" #include "utils/textinputdialog.hpp" @@ -46,9 +47,10 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) return index1.row() <= index2.row(); } -DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) - : QWidget(parent) - , mCfgMgr(cfg) +DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, QWidget *parent) + : mCfgMgr(cfg) + , mGameSettings(gameSettings) + , QWidget(parent) { // Models mMastersModel = new DataFilesModel(this); @@ -178,6 +180,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) createActions(); setupConfig(); + setupDataFiles(); } void DataFilesPage::createActions() @@ -340,269 +343,176 @@ void DataFilesPage::readConfig() } -bool DataFilesPage::showDataFilesWarning() +void DataFilesPage::setupDataFiles() { + // Set the encoding to the one found in openmw.cfg or the default + mMastersModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); + mPluginsModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); - QMessageBox msgBox; - msgBox.setWindowTitle("Error detecting Morrowind installation"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("
Could not find the Data Files location

\ - The directory containing the data files was not found.

\ - Press \"Browse...\" to specify the location manually.
")); + QStringList paths = mGameSettings.getDataDirs(); - QAbstractButton *dirSelectButton = - msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); - - msgBox.exec(); - - if (msgBox.clickedButton() == dirSelectButton) { - - // Show a custom dir selection dialog which only accepts valid dirs - QString selectedDir = FileDialog::getExistingDirectory( - this, tr("Select Data Files Directory"), - QDir::currentPath(), - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - - // Add the user selected data directory - if (!selectedDir.isEmpty()) { - mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); - mCfgMgr.processPaths(mDataDirs); - } else { - // Cancel from within the dir selection dialog - return false; - } - - } else { - // Cancel - return false; - } - - return true; -} - -bool DataFilesPage::setupDataFiles() -{ - // We use the Configuration Manager to retrieve the configuration values - boost::program_options::variables_map variables; - boost::program_options::options_description desc; - - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) - ("data-local", boost::program_options::value()->default_value("")) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("encoding", boost::program_options::value()->default_value("win1252")); - - boost::program_options::notify(variables); - - mCfgMgr.readConfiguration(variables, desc); - - if (variables["data"].empty()) { - if (!showDataFilesWarning()) - return false; - } else { - mDataDirs = Files::PathContainer(variables["data"].as()); - } - - std::string local = variables["data-local"].as(); - if (!local.empty()) { - mDataLocal.push_back(Files::PathContainer::value_type(local)); - } - - mCfgMgr.processPaths(mDataDirs); - mCfgMgr.processPaths(mDataLocal); - - // Second chance to display the warning, the data= entries are invalid - while (mDataDirs.empty()) { - if (!showDataFilesWarning()) - return false; - } - - // Set the charset for reading the esm/esp files - QString encoding = QString::fromStdString(variables["encoding"].as()); - if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { - mMastersModel->setEncoding(encoding); - mPluginsModel->setEncoding(encoding); - } - - // Add the paths to the respective models - for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { - QString path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); + foreach (const QString &path, paths) { mMastersModel->addMasters(path); mPluginsModel->addPlugins(path); } - // Same for the data-local paths - for (Files::PathContainer::iterator it = mDataLocal.begin(); it != mDataLocal.end(); ++it) { - QString path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - mMastersModel->addMasters(path); - mPluginsModel->addPlugins(path); + QString dataLocal = mGameSettings.getDataLocal(); + if (!dataLocal.isEmpty()) { + mMastersModel->addMasters(dataLocal); + mPluginsModel->addPlugins(dataLocal); } - mMastersModel->sort(0); - mPluginsModel->sort(0); -// mMastersTable->sortByColumn(3, Qt::AscendingOrder); -// mPluginsTable->sortByColumn(3, Qt::AscendingOrder); - - - readConfig(); - return true; } void DataFilesPage::writeConfig(QString profile) { - // Don't overwrite the config if no masters are found - if (mMastersModel->rowCount() < 1) - return; +// // Don't overwrite the config if no masters are found +// if (mMastersModel->rowCount() < 1) +// return; - QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); - QDir userPath(pathStr); +// QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); +// QDir userPath(pathStr); - if (!userPath.exists()) { - if (!userPath.mkpath(pathStr)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error creating OpenMW configuration directory"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not create %0

\ - Please make sure you have the right permissions and try again.
").arg(pathStr)); - msgBox.exec(); +// if (!userPath.exists()) { +// if (!userPath.mkpath(pathStr)) { +// QMessageBox msgBox; +// msgBox.setWindowTitle("Error creating OpenMW configuration directory"); +// msgBox.setIcon(QMessageBox::Critical); +// msgBox.setStandardButtons(QMessageBox::Ok); +// msgBox.setText(tr("
Could not create %0

\ +// Please make sure you have the right permissions and try again.
").arg(pathStr)); +// msgBox.exec(); - qApp->quit(); - return; - } - } - // Open the OpenMW config as a QFile - QFile file(pathStr.append("openmw.cfg")); +// qApp->quit(); +// return; +// } +// } +// // Open the OpenMW config as a QFile +// QFile file(pathStr.append("openmw.cfg")); - if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { - // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not open or create %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); - msgBox.exec(); +// if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { +// // File cannot be opened or created +// QMessageBox msgBox; +// msgBox.setWindowTitle("Error writing OpenMW configuration file"); +// msgBox.setIcon(QMessageBox::Critical); +// msgBox.setStandardButtons(QMessageBox::Ok); +// msgBox.setText(tr("
Could not open or create %0

\ +// Please make sure you have the right permissions and try again.
").arg(file.fileName())); +// msgBox.exec(); - qApp->quit(); - return; - } +// qApp->quit(); +// return; +// } - QTextStream in(&file); - QByteArray buffer; +// QTextStream in(&file); +// QByteArray buffer; - // Remove all previous entries from config - while (!in.atEnd()) { - QString line = in.readLine(); - if (!line.startsWith("master") && - !line.startsWith("plugin") && - !line.startsWith("data") && - !line.startsWith("data-local")) - { - buffer += line += "\n"; - } - } +// // Remove all previous entries from config +// while (!in.atEnd()) { +// QString line = in.readLine(); +// if (!line.startsWith("master") && +// !line.startsWith("plugin") && +// !line.startsWith("data") && +// !line.startsWith("data-local")) +// { +// buffer += line += "\n"; +// } +// } - file.close(); +// file.close(); - // Now we write back the other config entries - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not write to %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); - msgBox.exec(); +// // Now we write back the other config entries +// if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { +// QMessageBox msgBox; +// msgBox.setWindowTitle("Error writing OpenMW configuration file"); +// msgBox.setIcon(QMessageBox::Critical); +// msgBox.setStandardButtons(QMessageBox::Ok); +// msgBox.setText(tr("
Could not write to %0

\ +// Please make sure you have the right permissions and try again.
").arg(file.fileName())); +// msgBox.exec(); - qApp->quit(); - return; - } +// qApp->quit(); +// return; +// } - if (!buffer.isEmpty()) { - file.write(buffer); - } +// if (!buffer.isEmpty()) { +// file.write(buffer); +// } - QTextStream gameConfig(&file); - - // First write the list of data dirs - mCfgMgr.processPaths(mDataDirs); - mCfgMgr.processPaths(mDataLocal); - - QString path; - - // data= directories - for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { - path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - - // Make sure the string is quoted when it contains spaces - if (path.contains(" ")) { - gameConfig << "data=\"" << path << "\"" << endl; - } else { - gameConfig << "data=" << path << endl; - } - } - - // data-local directory - if (!mDataLocal.empty()) { - path = QString::fromStdString(mDataLocal.front().string()); - path.remove(QChar('\"')); - - if (path.contains(" ")) { - gameConfig << "data-local=\"" << path << "\"" << endl; - } else { - gameConfig << "data-local=" << path << endl; - } - } +// QTextStream gameConfig(&file); - if (profile.isEmpty()) - profile = mProfilesComboBox->currentText(); +// QString path; - if (profile.isEmpty()) - return; +// // data= directories +// for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { +// path = QString::fromStdString(it->string()); +// path.remove(QChar('\"')); - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } +// // Make sure the string is quoted when it contains spaces +// if (path.contains(" ")) { +// gameConfig << "data=\"" << path << "\"" << endl; +// } else { +// gameConfig << "data=" << path << endl; +// } +// } - mLauncherConfig->beginGroup("Profiles"); - mLauncherConfig->setValue("CurrentProfile", profile); +// // data-local directory +// if (!mDataLocal.empty()) { +// path = QString::fromStdString(mDataLocal.front().string()); +// path.remove(QChar('\"')); - // Open the profile-name subgroup - mLauncherConfig->beginGroup(profile); - mLauncherConfig->remove(""); // Clear the subgroup +// if (path.contains(" ")) { +// gameConfig << "data-local=\"" << path << "\"" << endl; +// } else { +// gameConfig << "data-local=" << path << endl; +// } +// } - // Now write the masters to the configs - const QStringList masters = mMastersModel->checkedItems(); - // We don't use foreach because we need i - for (int i = 0; i < masters.size(); ++i) { - const QString currentMaster = masters.at(i); +// if (profile.isEmpty()) +// profile = mProfilesComboBox->currentText(); - mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster); - gameConfig << "master=" << currentMaster << endl; +// if (profile.isEmpty()) +// return; - } +// // Make sure we have no groups open +// while (!mLauncherConfig->group().isEmpty()) { +// mLauncherConfig->endGroup(); +// } - // And finally write all checked plugins - const QStringList plugins = mPluginsModel->checkedItems(); +// mLauncherConfig->beginGroup("Profiles"); +// mLauncherConfig->setValue("CurrentProfile", profile); - for (int i = 0; i < plugins.size(); ++i) { - const QString currentPlugin = plugins.at(i); - mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin); - gameConfig << "plugin=" << currentPlugin << endl; - } +// // Open the profile-name subgroup +// mLauncherConfig->beginGroup(profile); +// mLauncherConfig->remove(""); // Clear the subgroup - file.close(); - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - mLauncherConfig->sync(); +// // Now write the masters to the configs +// const QStringList masters = mMastersModel->checkedItems(); + +// // We don't use foreach because we need i +// for (int i = 0; i < masters.size(); ++i) { +// const QString currentMaster = masters.at(i); + +// mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster); +// gameConfig << "master=" << currentMaster << endl; + +// } + +// // And finally write all checked plugins +// const QStringList plugins = mPluginsModel->checkedItems(); + +// for (int i = 0; i < plugins.size(); ++i) { +// const QString currentPlugin = plugins.at(i); +// mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin); +// gameConfig << "plugin=" << currentPlugin << endl; +// } + +// file.close(); +// mLauncherConfig->endGroup(); +// mLauncherConfig->endGroup(); +// mLauncherConfig->sync(); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 13668ec30e..e40d29d602 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -3,9 +3,6 @@ #include #include -#include "utils/profilescombobox.hpp" -#include - class QTableView; class QSortFilterProxyModel; @@ -17,6 +14,8 @@ class ProfilesComboBox; class DataFilesModel; class TextInputDialog; +class ProfilesComboBox; +class GameSettings; namespace Files { struct ConfigurationManager; } @@ -25,13 +24,11 @@ class DataFilesPage : public QWidget Q_OBJECT public: - DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); + DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, QWidget *parent = 0); ProfilesComboBox *mProfilesComboBox; void writeConfig(QString profile = QString()); - bool showDataFilesWarning(); - bool setupDataFiles(); public slots: void setCheckState(QModelIndex index); @@ -76,10 +73,9 @@ private: QAction *mUncheckAction; Files::ConfigurationManager &mCfgMgr; - Files::PathContainer mDataDirs; - Files::PathContainer mDataLocal; QSettings *mLauncherConfig; + GameSettings &mGameSettings; TextInputDialog *mNewProfileDialog; @@ -87,6 +83,7 @@ private: // const QStringList selectedMasters(); void createActions(); + void setupDataFiles(); void setupConfig(); void readConfig(); diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2c4f3430c5..fa9d5d2547 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -3,12 +3,12 @@ #include #include -#include #include #include -#include +//#include +#include "settings/graphicssettings.hpp" #include "utils/naturalsort.hpp" #include "graphicspage.hpp" @@ -25,9 +25,10 @@ QString getAspect(int x, int y) return QString(QString::number(xaspect) + ":" + QString::number(yaspect)); } -GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent) - : QWidget(parent) - , mCfgMgr(cfg) +GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent) + : mCfgMgr(cfg) + , mGraphicsSettings(graphicsSetting) + , QWidget(parent) { QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this); @@ -117,9 +118,8 @@ bool GraphicsPage::setupOgre() #endif } - boost::filesystem::path absPluginPath = boost::filesystem::absolute(boost::filesystem::path(pluginDir)); - - pluginDir = absPluginPath.string(); + QDir dir(QString::fromStdString(pluginDir)); + pluginDir = dir.absolutePath().toStdString(); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mOgre); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mOgre); @@ -154,20 +154,16 @@ bool GraphicsPage::setupOgre() msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not select a valid render system

\ - Please make sure the plugins.cfg file exists and contains a valid rendering plugin.
")); + Please make sure the plugins.cfg file exists and contains a valid rendering plugin.
")); msgBox.exec(); - return false; } // Now fill the GUI elements - int index = mRendererComboBox->findText(QString::fromStdString(Settings::Manager::getString("render system", "Video"))); - + int index = mRendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system"))); if ( index != -1) { mRendererComboBox->setCurrentIndex(index); - } - else - { + } else { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(direct3DName)); #else @@ -180,45 +176,49 @@ bool GraphicsPage::setupOgre() mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); - readConfig(); + // Load the rest of the values + loadSettings(); return true; } -void GraphicsPage::readConfig() +void GraphicsPage::loadSettings() { - if (Settings::Manager::getBool("vsync", "Video")) - mVSyncCheckBox->setCheckState(Qt::Checked); + if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) + mVSyncCheckBox->setCheckState(Qt::Checked); - if (Settings::Manager::getBool("fullscreen", "Video")) - mFullScreenCheckBox->setCheckState(Qt::Checked); + if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) + mFullScreenCheckBox->setCheckState(Qt::Checked); - int aaIndex = mAntiAliasingComboBox->findText(QString::fromStdString(Settings::Manager::getString("antialiasing", "Video"))); - if (aaIndex != -1) - mAntiAliasingComboBox->setCurrentIndex(aaIndex); + int aaIndex = mAntiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); + if (aaIndex != -1) + mAntiAliasingComboBox->setCurrentIndex(aaIndex); - QString resolution = QString::number(Settings::Manager::getInt("resolution x", "Video")); - resolution.append(" x " + QString::number(Settings::Manager::getInt("resolution y", "Video"))); + QString resolution = mGraphicsSettings.value(QString("Video/resolution x")); + resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); - int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); - if (resIndex != -1) - mResolutionComboBox->setCurrentIndex(resIndex); + int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); + qDebug() << "resolution from file: " << resolution; + if (resIndex != -1) + mResolutionComboBox->setCurrentIndex(resIndex); } -void GraphicsPage::writeConfig() +void GraphicsPage::saveSettings() { - Settings::Manager::setBool("vsync", "Video", mVSyncCheckBox->checkState()); - Settings::Manager::setBool("fullscreen", "Video", mFullScreenCheckBox->checkState()); - Settings::Manager::setString("antialiasing", "Video", mAntiAliasingComboBox->currentText().toStdString()); - Settings::Manager::setString("render system", "Video", mRendererComboBox->currentText().toStdString()); + mVSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true")) + : mGraphicsSettings.setValue(QString("Video/vsync"), QString("false")); - // Get the current resolution, but with the tabs replaced with a single space - QString resolution = mResolutionComboBox->currentText().simplified(); - QStringList tokens = resolution.split(" ", QString::SkipEmptyParts); + mFullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) + : mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false")); - int resX = tokens.at(0).toInt(); - int resY = tokens.at(2).toInt(); - Settings::Manager::setInt("resolution x", "Video", resX); - Settings::Manager::setInt("resolution y", "Video", resY); + mGraphicsSettings.setValue(QString("Video/antialiasing"), mAntiAliasingComboBox->currentText()); + mGraphicsSettings.setValue(QString("Video/render system"), mRendererComboBox->currentText()); + + QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); + + if (resolutionRe.exactMatch(mResolutionComboBox->currentText().simplified())) { + mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); + mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + } } QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer) @@ -232,16 +232,14 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy { Ogre::StringVector::iterator opt_it; uint idx = 0; - for (opt_it = i->second.possibleValues.begin (); - opt_it != i->second.possibleValues.end (); opt_it++, idx++) - { - if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) - { + for (opt_it = i->second.possibleValues.begin(); + opt_it != i->second.possibleValues.end(); opt_it++, idx++) + { + if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); } } - } // Sort ascending @@ -258,7 +256,7 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) { - QString key ("Video Mode"); + QString key("Video Mode"); QStringList result; uint row = 0; diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index b8166f672a..48b9ff7854 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -5,8 +5,8 @@ #include #include -#include -#include +//#include +//#include // Static plugin headers #ifdef ENABLE_PLUGIN_GL @@ -21,6 +21,8 @@ class QCheckBox; class QStackedWidget; class QSettings; +class GraphicsSettings; + namespace Files { struct ConfigurationManager; } class GraphicsPage : public QWidget @@ -28,10 +30,10 @@ class GraphicsPage : public QWidget Q_OBJECT public: - GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent = 0); + GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0); + void saveSettings(); bool setupOgre(); - void writeConfig(); public slots: void rendererChanged(const QString &renderer); @@ -58,12 +60,14 @@ private: QCheckBox *mFullScreenCheckBox; Files::ConfigurationManager &mCfgMgr; + GraphicsSettings &mGraphicsSettings; QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); QStringList getAvailableResolutions(Ogre::RenderSystem *renderer); void createPages(); - void readConfig(); + void loadSettings(); + }; #endif diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 3fef62bc65..43bf50fbc7 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -138,9 +138,7 @@ int main(int argc, char *argv[]) paths.clear(); paths.append(globalPath + QString("settings-default.cfg")); paths.append(QString("settings-default.cfg")); - paths.append(userPath + QString("settings.cfg")); - paths.append(QString("settings.cfg")); foreach (const QString &path, paths) { qDebug() << "Loading: " << path; @@ -166,14 +164,14 @@ int main(int argc, char *argv[]) } - MainDialog mainWin; - mainWin.setup(); + MainDialog mainWin(gameSettings, graphicsSettings); + + if (mainWin.setup()) { + mainWin.show(); + } else { + return 0; + } - mainWin.show(); - QCoreApplication::processEvents(); return app.exec(); - - - return 0; } diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 674ccdf672..4d3d24bd91 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,11 +1,20 @@ #include +#include "settings/gamesettings.hpp" +#include "settings/graphicssettings.hpp" + +#include "utils/profilescombobox.hpp" + #include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" #include "datafilespage.hpp" -MainDialog::MainDialog() +MainDialog::MainDialog(GameSettings &gameSettings, + GraphicsSettings &graphicsSettings) + : mGameSettings(gameSettings) + , mGraphicsSettings(graphicsSettings) + { QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); @@ -122,8 +131,8 @@ void MainDialog::createIcons() void MainDialog::createPages() { mPlayPage = new PlayPage(this); - mGraphicsPage = new GraphicsPage(mCfgMgr, this); - mDataFilesPage = new DataFilesPage(mCfgMgr, this); + mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this); + mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); @@ -152,46 +161,17 @@ void MainDialog::createPages() bool MainDialog::setup() { - // Create the settings manager and load default settings file - const std::string localdefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); - const std::string globaldefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); - - // prefer local - if (boost::filesystem::exists(localdefault)) { - mSettings.loadDefault(localdefault); - } else if (boost::filesystem::exists(globaldefault)) { - mSettings.loadDefault(globaldefault); - } else { - QMessageBox msgBox; - msgBox.setWindowTitle("Error reading OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not find %0

\ - The problem may be due to an incomplete installation of OpenMW.
\ - Reinstalling OpenMW may resolve the problem.").arg(QString::fromStdString(globaldefault))); - msgBox.exec(); - return false; - } - - // load user settings if they exist, otherwise just load the default settings as user settings - const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); - - if (boost::filesystem::exists(settingspath)) - mSettings.loadUser(settingspath); - else if (boost::filesystem::exists(localdefault)) - mSettings.loadUser(localdefault); - else if (boost::filesystem::exists(globaldefault)) - mSettings.loadUser(globaldefault); - // Setup the Graphics page if (!mGraphicsPage->setupOgre()) { return false; } // Setup the Data Files page + /* if (!mDataFilesPage->setupDataFiles()) { return false; - } + }*/ + return true; } @@ -208,11 +188,67 @@ void MainDialog::closeEvent(QCloseEvent *event) { // Now write all config files mDataFilesPage->writeConfig(); - mGraphicsPage->writeConfig(); + mGraphicsPage->saveSettings(); - // Save user settings - const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); - mSettings.saveUser(settingspath); + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + QDir dir(userPath); + + if (!dir.exists()) { + if (!dir.mkpath(userPath)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error creating OpenMW configuration directory"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not create %0

\ + Please make sure you have the right permissions \ + and try again.
").arg(userPath)); + msgBox.exec(); + event->accept(); + } + } + + // Game settings + QFile file(userPath + QString("openmw.cfg")); + + if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0 for writing

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + event->accept(); + } + + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mGameSettings.writeFile(stream); + file.close(); + + // Graphics settings + file.setFileName(userPath + QString("settings.cfg")); + + if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0 for writing

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + event->accept(); + } + + stream.setDevice(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mGraphicsSettings.writeFile(stream); event->accept(); } @@ -221,7 +257,7 @@ void MainDialog::play() { // First do a write of all the configs, just to be sure mDataFilesPage->writeConfig(); - mGraphicsPage->writeConfig(); + //mGraphicsPage->writeConfig(); // Save user settings const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index bf98011cc4..c9654b874c 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -17,12 +17,15 @@ class PlayPage; class GraphicsPage; class DataFilesPage; +class GameSettings; +class GraphicsSettings; + class MainDialog : public QMainWindow { Q_OBJECT public: - MainDialog(); + MainDialog(GameSettings &gameSettings, GraphicsSettings &GraphicsSettings); public slots: void changePage(QListWidgetItem *current, QListWidgetItem *previous); @@ -43,6 +46,10 @@ private: Files::ConfigurationManager mCfgMgr; Settings::Manager mSettings; + + GameSettings &mGameSettings; + GraphicsSettings &mGraphicsSettings; + }; #endif diff --git a/apps/launcher/utils/filedialog.cpp b/apps/launcher/utils/filedialog.cpp deleted file mode 100644 index 16d6775331..0000000000 --- a/apps/launcher/utils/filedialog.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "filedialog.hpp" -#include -#include - -FileDialog::FileDialog(QWidget *parent) - : QFileDialog(parent) -{ - // Remove the default Choose button to prevent it being updated elsewhere - QDialogButtonBox *box = qFindChild(this); - Q_ASSERT(box); - box->removeButton(box->button(QDialogButtonBox::Open)); - - // Add our own button so we can disable/enable it - mChooseButton = new QPushButton(tr("&Choose")); - mChooseButton->setIcon(QIcon::fromTheme("document-open")); - mChooseButton->setEnabled(false); - box->addButton(mChooseButton, QDialogButtonBox::AcceptRole); - - connect(this, SIGNAL(directoryEntered(const QString&)), this, SLOT(updateChooseButton(const QString&))); - emit directoryEntered(QDir::currentPath()); -} - -QString FileDialog::getExistingDirectory(QWidget *parent, - const QString &caption, - const QString &dir, - Options options) -{ - // create a non-native file dialog - FileDialog dialog; - dialog.setFileMode(DirectoryOnly); - dialog.setOptions(options |= QFileDialog::DontUseNativeDialog | QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly); - - if (!caption.isEmpty()) - dialog.setWindowTitle(caption); - - if (!dir.isEmpty()) - dialog.setDirectory(dir); - - if (dialog.exec() == QDialog::Accepted) { - return dialog.selectedFiles().value(0); - } - return QString(); -} - -void FileDialog::updateChooseButton(const QString &directory) -{ - QDir currentDir = QDir(directory); - currentDir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); - currentDir.setNameFilters(QStringList() << "*.esm" << "*.esp"); - - if (!currentDir.entryList().isEmpty()) { - // There are data files in the current dir - mChooseButton->setEnabled(true); - } else { - mChooseButton->setEnabled(false); - } -} diff --git a/apps/launcher/utils/filedialog.hpp b/apps/launcher/utils/filedialog.hpp deleted file mode 100644 index 7a161ecb96..0000000000 --- a/apps/launcher/utils/filedialog.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef FILEDIALOG_HPP -#define FILEDIALOG_HPP - -#include - -class QPushButton; - -class FileDialog : public QFileDialog -{ - Q_OBJECT - -public: - FileDialog(QWidget *parent = 0); - - static QString getExistingDirectory(QWidget *parent = 0, - const QString &caption = QString(), - const QString &dir = QString(), - Options options = ShowDirsOnly); - -private slots: - void updateChooseButton(const QString &directory); - -private: - QPushButton *mChooseButton; -}; - - -#endif // FILEDIALOG_HPP From e1d39331454e5839e4248941f7b4037e0755b69e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 01:27:12 -0800 Subject: [PATCH 0165/1483] Remove an unused struct --- components/nifogre/ogre_nif_loader.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index ce0fb00fcd..e5e949d0ee 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -355,15 +355,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc } -/* Comparitor to help sort Key<> 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; From 7df4d0d19fdb081fb6e813c7c327ad38695a8da1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 21:41:51 -0800 Subject: [PATCH 0166/1483] Remove an unnecessary cast --- apps/openmw/mwrender/animation.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a36155dbed..c4439841fe 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -102,11 +102,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(trackiter.hasMoreElements()) { const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); - const Ogre::Node *srcbone = dynamic_cast(srcnode); - if(!srcbone || !skelinst->hasBone(srcbone->getName())) + if(!skelinst->hasBone(srcnode->getName())) continue; - Ogre::Bone *bone = skelinst->getBone(srcbone->getName()); + Ogre::Bone *bone = skelinst->getBone(srcnode->getName()); bone->setOrientation(Ogre::Quaternion::IDENTITY); bone->setPosition(Ogre::Vector3::ZERO); bone->setScale(Ogre::Vector3(1.0f)); From 487c83e94305efb7becf4682feb9c80e9998f99d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 22:09:41 -0800 Subject: [PATCH 0167/1483] Rename nonaccum to animroot --- components/nifogre/ogre_nif_loader.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e5e949d0ee..8dbfbff5a4 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -305,7 +305,7 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) } -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonaccum, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { if(node->recType == Nif::RC_NiTriShape) return; @@ -326,18 +326,18 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc while(!ctrl.empty()) { if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); + ctrls.push_back(static_cast(ctrl.getPtr())); ctrl = ctrl->next; } Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiTextKeyExtraData && !nonaccum) + if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); - nonaccum = bone; + animroot = bone; } e = e->extra; } @@ -349,7 +349,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), nonaccum, textkeys, ctrls, bone); + buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); } } } @@ -369,10 +369,10 @@ void loadResource(Ogre::Resource *resource) const Nif::Node *node = dynamic_cast(nif.getRecord(0)); std::vector ctrls; - Ogre::Bone *nonaccum = NULL; + Ogre::Bone *animroot = NULL; TextKeyMap textkeys; try { - buildBones(skel, node, nonaccum, textkeys, ctrls); + buildBones(skel, node, animroot, textkeys, ctrls); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() <getName()+", but no text keys. Uses NiBSAnimationNode?"); return; } - Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); + Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); std::string currentgroup; From 8d98f3649c356dd0e88fba1397d0ccb5cca47f22 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 23:39:11 -0800 Subject: [PATCH 0168/1483] Use a separate class to handle activator mechanics --- apps/openmw/CMakeLists.txt | 5 +- apps/openmw/mwbase/mechanicsmanager.hpp | 14 ++--- apps/openmw/mwclass/activator.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/activators.cpp | 62 +++++++++++++++++++ apps/openmw/mwmechanics/activators.hpp | 42 +++++++++++++ apps/openmw/mwmechanics/actors.cpp | 14 +---- .../mwmechanics/mechanicsmanagerimp.cpp | 45 +++++++++----- .../mwmechanics/mechanicsmanagerimp.hpp | 19 +++--- apps/openmw/mwworld/scene.cpp | 8 +-- apps/openmw/mwworld/worldimp.cpp | 9 ++- 12 files changed, 168 insertions(+), 56 deletions(-) create mode 100644 apps/openmw/mwmechanics/activators.cpp create mode 100644 apps/openmw/mwmechanics/activators.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ec7700beee..73baa4e72e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,8 +62,9 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat character creaturestats magiceffects movement actors drawstate spells - activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate + mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators + drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow + aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index f7bbd6a9f9..ec616fcaf2 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -37,21 +37,21 @@ namespace MWBase virtual ~MechanicsManager() {} - virtual void addActor (const MWWorld::Ptr& ptr) = 0; - ///< Register an actor for stats management + virtual void add (const MWWorld::Ptr& ptr) = 0; + ///< Register an object for management - virtual void removeActor (const MWWorld::Ptr& ptr) = 0; - ///< Deregister an actor for stats management + virtual void remove (const MWWorld::Ptr& ptr) = 0; + ///< Deregister an object for management - virtual void dropActors (const MWWorld::CellStore *cellStore) = 0; - ///< Deregister all actors in the given cell. + virtual void drop (const MWWorld::CellStore *cellStore) = 0; + ///< Deregister all objects in the given cell. virtual void watchActor (const MWWorld::Ptr& ptr) = 0; ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. virtual void update (float duration, bool paused) = 0; - ///< Update actor stats and store desired velocity vectors in \a movement + ///< Update objects /// /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 2926272866..3a60d9c397 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -32,7 +32,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addObject(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor(ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Activator::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7b0f9f7289..90dc707152 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -97,7 +97,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addActor(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor (ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Creature::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cfbc64b87d..6069e3b7c7 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -142,7 +142,7 @@ namespace MWClass void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { physics.addActor(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor(ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Npc::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp new file mode 100644 index 0000000000..799d7ecd55 --- /dev/null +++ b/apps/openmw/mwmechanics/activators.cpp @@ -0,0 +1,62 @@ +#include "activators.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +Activators::Activators() +{ +} + +void Activators::addActivator (const MWWorld::Ptr& ptr) +{ + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); + mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); +} + +void Activators::removeActivator (const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + mActivators.erase(iter); +} + +void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) +{ + PtrControllerMap::iterator iter = mActivators.begin(); + while(iter != mActivators.end()) + { + if(iter->first.getCell()==cellStore) + mActivators.erase(iter++); + else + ++iter; + } +} + +void Activators::update(float duration, bool paused) +{ + if(!paused) + { + for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) + iter->second.update(duration); + } +} + +void Activators::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + iter->second.playGroup(groupName, mode, number); +} +void Activators::skipAnimation(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + iter->second.skipAnim(); +} + +} diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp new file mode 100644 index 0000000000..3ddb0f8432 --- /dev/null +++ b/apps/openmw/mwmechanics/activators.hpp @@ -0,0 +1,42 @@ +#ifndef GAME_MWMECHANICS_ACTIVATORS_H +#define GAME_MWMECHANICS_ACTOVATRS_H + +#include +#include + +#include "character.hpp" + +namespace MWWorld +{ + class Ptr; + class CellStore; +} + +namespace MWMechanics +{ + class Activators + { + typedef std::map PtrControllerMap; + PtrControllerMap mActivators; + + public: + Activators(); + + void addActivator (const MWWorld::Ptr& ptr); + ///< Register an activator + + void removeActivator (const MWWorld::Ptr& ptr); + ///< Deregister an activator + + void dropActivators (const MWWorld::CellStore *cellStore); + ///< Deregister all activators in the given cell. + + void update (float duration, bool paused); + ///< Update activator animations + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6c69c457bb..98ae3e7558 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,9 +166,7 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - /* Kind of a hack. Activators need a character controller to manage an idle state. */ - if(ptr.getTypeName() == typeid(ESM::Activator).name() || - !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) + if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); @@ -205,11 +203,6 @@ namespace MWMechanics PtrControllerMap::iterator iter(mActors.begin()); while(iter != mActors.end()) { - if(iter->first.getTypeName() == typeid(ESM::Activator).name()) - { - iter++; - continue; - } if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) @@ -304,10 +297,7 @@ namespace MWMechanics void Actors::restoreDynamicStats() { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - { - if(iter->first.getTypeName() != typeid(ESM::Activator).name()) - calculateRestoration(iter->first, 3600); - } + calculateRestoration(iter->first, 3600); } int Actors::countDeaths (const std::string& id) const diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 84145eb082..3e56cbcb12 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -175,33 +175,37 @@ namespace MWMechanics buildPlayer(); } - void MechanicsManager::addActor (const MWWorld::Ptr& ptr) + void MechanicsManager::add(const MWWorld::Ptr& ptr) { - mActors.addActor (ptr); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.addActivator(ptr); + else + mActors.addActor(ptr); } - void MechanicsManager::removeActor (const MWWorld::Ptr& ptr) + void MechanicsManager::remove(const MWWorld::Ptr& ptr) { - if (ptr==mWatched) + if(ptr == mWatched) + mWatched = MWWorld::Ptr(); + mActors.removeActor(ptr); + } + + void MechanicsManager::drop(const MWWorld::CellStore *cellStore) + { + if(!mWatched.isEmpty() && mWatched.getCell() == cellStore) mWatched = MWWorld::Ptr(); - mActors.removeActor (ptr); + mActors.dropActors(cellStore); + mActivators.dropActivators(cellStore); } - void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore) - { - if (!mWatched.isEmpty() && mWatched.getCell()==cellStore) - mWatched = MWWorld::Ptr(); - mActors.dropActors (cellStore); - } - - void MechanicsManager::watchActor (const MWWorld::Ptr& ptr) + void MechanicsManager::watchActor(const MWWorld::Ptr& ptr) { mWatched = ptr; } - void MechanicsManager::update (float duration, bool paused) + void MechanicsManager::update(float duration, bool paused) { if (!mWatched.isEmpty()) { @@ -297,7 +301,8 @@ namespace MWMechanics winMgr->configureSkills (majorSkills, minorSkills); } - mActors.update (duration, paused); + mActors.update(duration, paused); + mActivators.update(duration, paused); } void MechanicsManager::restoreDynamicStats() @@ -631,11 +636,17 @@ namespace MWMechanics void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - mActors.playAnimationGroup(ptr, groupName, mode, number); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.playAnimationGroup(ptr, groupName, mode, number); + else + mActors.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { - mActors.skipAnimation(ptr); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.skipAnimation(ptr); + else + mActors.skipAnimation(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index c2bbd96cfe..f70242bb98 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,6 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include "activators.hpp" #include "actors.hpp" namespace Ogre @@ -29,6 +30,8 @@ namespace MWMechanics bool mUpdatePlayer; bool mClassSelected; bool mRaceSelected; + + Activators mActivators; Actors mActors; void buildPlayer(); @@ -39,21 +42,21 @@ namespace MWMechanics MechanicsManager(); - virtual void addActor (const MWWorld::Ptr& ptr); - ///< Register an actor for stats management + virtual void add (const MWWorld::Ptr& ptr); + ///< Register an object for management - virtual void removeActor (const MWWorld::Ptr& ptr); - ///< Deregister an actor for stats management + virtual void remove (const MWWorld::Ptr& ptr); + ///< Deregister an object for management - virtual void dropActors (const MWWorld::CellStore *cellStore); - ///< Deregister all actors in the given cell. + virtual void drop(const MWWorld::CellStore *cellStore); + ///< Deregister all objects in the given cell. - virtual void watchActor (const MWWorld::Ptr& ptr); + virtual void watchActor(const MWWorld::Ptr& ptr); ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. virtual void update (float duration, bool paused); - ///< Update actor stats and store desired velocity vectors in \a movement + ///< Update objects /// /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index e116dca579..47751acb39 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -100,7 +100,7 @@ namespace MWWorld //mPhysics->removeObject("Unnamed_43"); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); - MWBase::Environment::get().getMechanicsManager()->dropActors (*iter); + MWBase::Environment::get().getMechanicsManager()->drop (*iter); MWBase::Environment::get().getSoundManager()->stopSound (*iter); mActiveCells.erase(*iter); } @@ -166,7 +166,7 @@ namespace MWWorld MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->addActor(player); + mechMgr->add(player); mechMgr->watchActor(player); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); @@ -179,7 +179,7 @@ namespace MWWorld mRendering.preCellChange(mCurrentCell); // remove active - MWBase::Environment::get().getMechanicsManager()->removeActor (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); CellStoreCollection::iterator active = mActiveCells.begin(); @@ -443,7 +443,7 @@ namespace MWWorld void Scene::removeObjectFromScene (const Ptr& ptr) { - MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); + MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->removeObject (ptr.getRefData().getHandle()); mRendering.removeObject (ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0888a45221..a1d713a8aa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -700,6 +700,7 @@ namespace MWWorld if (*currCell != newCell) { if (isPlayer) + { if (!newCell.isExterior()) changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos); else @@ -708,7 +709,9 @@ namespace MWWorld int cellY = newCell.mCell->getGridY(); mWorldScene->changeCell(cellX, cellY, pos, false); } - else { + } + else + { if (!mWorldScene->isCellActive(*currCell)) copyObjectToCell(ptr, newCell, pos); else if (!mWorldScene->isCellActive(newCell)) @@ -732,8 +735,8 @@ namespace MWWorld MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->removeActor(ptr); - mechMgr->addActor(copy); + mechMgr->remove(ptr); + mechMgr->add(copy); } else { From fdabef65a1ccae23007a720a224d6e76dfd3ea12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:19:24 -0800 Subject: [PATCH 0169/1483] Use a method to update an object's cell in the mechanics manager This prevents destroying and recreating the object's character controller (and messing up the current animation) when moving between cells. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +++ apps/openmw/mwmechanics/activators.cpp | 11 ++++++++++ apps/openmw/mwmechanics/activators.hpp | 3 +++ apps/openmw/mwmechanics/actors.cpp | 11 ++++++++++ apps/openmw/mwmechanics/actors.hpp | 3 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 9 ++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 22 +++++-------------- 8 files changed, 49 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index ec616fcaf2..cb9539ef65 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -43,6 +43,9 @@ namespace MWBase virtual void remove (const MWWorld::Ptr& ptr) = 0; ///< Deregister an object for management + virtual void updateCell(const MWWorld::Ptr &ptr) = 0; + ///< Moves an object to a new cell + virtual void drop (const MWWorld::CellStore *cellStore) = 0; ///< Deregister all objects in the given cell. diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 799d7ecd55..20b7865f53 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -25,6 +25,17 @@ void Activators::removeActivator (const MWWorld::Ptr& ptr) mActivators.erase(iter); } +void Activators::updateActivatorCell(const MWWorld::Ptr &ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + { + CharacterController ctrl = iter->second; + mActivators.erase(iter); + mActivators.insert(std::make_pair(ptr, ctrl)); + } +} + void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) { PtrControllerMap::iterator iter = mActivators.begin(); diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 3ddb0f8432..5c3eba2206 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -28,6 +28,9 @@ namespace MWMechanics void removeActivator (const MWWorld::Ptr& ptr); ///< Deregister an activator + void updateActivatorCell(const MWWorld::Ptr& ptr); + ///< Updates an activator with a new cell store + void dropActivators (const MWWorld::CellStore *cellStore); ///< Deregister all activators in the given cell. diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 98ae3e7558..27b7ad14e9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -179,6 +179,17 @@ namespace MWMechanics mActors.erase(iter); } + void Actors::updateActorCell(const MWWorld::Ptr &ptr) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + { + CharacterController ctrl = iter->second; + mActors.erase(iter); + mActors.insert(std::make_pair(ptr, ctrl)); + } + } + void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) { PtrControllerMap::iterator iter = mActors.begin(); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6fed9eff73..8c3df6c281 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -53,6 +53,9 @@ namespace MWMechanics /// /// \note Ignored, if \a ptr is not a registered actor. + void updateActorCell(const MWWorld::Ptr& ptr); + ///< Updates an actor with a new cell store + void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3e56cbcb12..9e76084f5a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -190,6 +190,15 @@ namespace MWMechanics mActors.removeActor(ptr); } + void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) + { + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.updateActivatorCell(ptr); + else + mActors.updateActorCell(ptr); + } + + void MechanicsManager::drop(const MWWorld::CellStore *cellStore) { if(!mWatched.isEmpty() && mWatched.getCell() == cellStore) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f70242bb98..99010b7ffd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -48,6 +48,9 @@ namespace MWMechanics virtual void remove (const MWWorld::Ptr& ptr); ///< Deregister an object for management + virtual void updateCell(const MWWorld::Ptr &ptr); + ///< Moves an object to a new cell + virtual void drop(const MWWorld::CellStore *cellStore); ///< Deregister all objects in the given cell. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a1d713a8aa..84a6b1b3df 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -729,24 +729,14 @@ namespace MWWorld addContainerScripts(copy, &newCell); mRendering->moveObjectToCell(copy, vec, currCell); + MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); + mechMgr->updateCell(copy); - if (MWWorld::Class::get(ptr).isActor()) + std::string script = MWWorld::Class::get(ptr).getScript(ptr); + if(!script.empty()) { - MWBase::MechanicsManager *mechMgr = - MWBase::Environment::get().getMechanicsManager(); - - mechMgr->remove(ptr); - mechMgr->add(copy); - } - else - { - std::string script = - MWWorld::Class::get(ptr).getScript(ptr); - if (!script.empty()) - { - mLocalScripts.remove(ptr); - mLocalScripts.add(script, copy); - } + mLocalScripts.remove(ptr); + mLocalScripts.add(script, copy); } } ptr.getRefData().setCount(0); From 92d0c55f32bf9e2ee8d6a850bdd4b2d4e4fff82c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:43:42 -0800 Subject: [PATCH 0170/1483] Add a flag to specify if an animation should be playing --- apps/openmw/mwrender/animation.cpp | 13 ++++++++++--- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c4439841fe..b0f21da847 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mPlaying(false) , mLooping(false) , mAnimSpeedMult(1.0f) { @@ -187,6 +188,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; reset(start); + mPlaying = true; } catch(std::exception &e) { std::cerr<< e.what() < 0.0f) + while(mAnimState && mPlaying && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); + mPlaying = (targetTime < mAnimState->getLength() || mLooping); break; } @@ -236,8 +239,12 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mAnimState->getTimePosition() >= time) break; } - else if(mController) - mController->markerEvent(time, evt); + else + { + mPlaying = false; + if(mController) + mController->markerEvent(time, evt); + } continue; } if(mController) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ed9c6eb192..091c2f2278 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,7 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + bool mPlaying; bool mLooping; float mAnimSpeedMult; From 879359f39d35cc88724b251231543bc76bda0bd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:50:52 -0800 Subject: [PATCH 0171/1483] Set the animation state loop flag as appropriate --- apps/openmw/mwrender/animation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b0f21da847..9666e62f4a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -184,6 +184,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); + mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; From 99efe4e494f449950877e08ca93a9d43a99adc1b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:02:55 -0800 Subject: [PATCH 0172/1483] Remove an unnecessary class member --- apps/openmw/mwrender/animation.cpp | 8 +++----- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9666e62f4a..778efc8132 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -27,7 +27,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentKeys(NULL) , mAnimState(NULL) , mPlaying(false) - , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -187,7 +186,6 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; - mLooping = loop; reset(start); mPlaying = true; } @@ -206,7 +204,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (targetTime < mAnimState->getLength() || mLooping); + mPlaying = (mAnimState->getLoop() || mAnimState->getLength() >= targetTime); break; } @@ -224,7 +222,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "loop stop") { - if(mLooping) + if(mAnimState->getLoop()) { reset("loop start"); if(mAnimState->getTimePosition() >= time) @@ -234,7 +232,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "stop") { - if(mLooping) + if(mAnimState->getLoop()) { reset("loop start"); if(mAnimState->getTimePosition() >= time) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 091c2f2278..5fa1bd85c7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -32,7 +32,6 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; bool mPlaying; - bool mLooping; float mAnimSpeedMult; From d4ddaa3d9585411c9f7c7a8a90e12de2ce517db0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:08:52 -0800 Subject: [PATCH 0173/1483] Only register activators that have a MWRender::Animation object --- apps/openmw/mwmechanics/activators.cpp | 5 +++-- apps/openmw/mwmechanics/activators.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 20b7865f53..1a743cad59 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -12,10 +12,11 @@ Activators::Activators() { } -void Activators::addActivator (const MWWorld::Ptr& ptr) +void Activators::addActivator(const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); + if(anim != NULL) + mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); } void Activators::removeActivator (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 5c3eba2206..0b9e984aa6 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -23,7 +23,7 @@ namespace MWMechanics Activators(); void addActivator (const MWWorld::Ptr& ptr); - ///< Register an activator + ///< Register an animated activator void removeActivator (const MWWorld::Ptr& ptr); ///< Deregister an activator From 0853fa335c2545a7ada380315b18078736d72ed6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:36:17 -0800 Subject: [PATCH 0174/1483] Avoid redundant string concatenations --- components/nifogre/ogre_nif_loader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8dbfbff5a4..d1bf803f13 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1204,14 +1204,14 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = bonename; + std::string filter = "@shape=tri "+bonename; Misc::StringUtils::toLower(filter); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) + if(meshes[i].mMeshName.find(filter) == std::string::npos) { sceneMgr->destroyEntity(ent); continue; From 04d4c125ba85775c8ca8e1c17e5f7122fbab444c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 02:00:42 -0800 Subject: [PATCH 0175/1483] Print when an animation event is unhandled --- apps/openmw/mwmechanics/character.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 83326d25af..6e78adfa4f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -122,6 +122,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) } return; } + + std::cerr<< "Unhandled animation event: "< Date: Wed, 30 Jan 2013 02:38:50 -0800 Subject: [PATCH 0176/1483] Make sure the player node's visibility cascades --- apps/openmw/mwrender/player.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 8f3e130395..9ab8a7de33 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -129,11 +129,8 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - mPlayerNode->setVisible( - mVanity.enabled || mPreviewMode || !mFirstPersonView, - false - ); - + /// \fixme We shouldn't hide the whole model, just certain components of the character (head, chest, feet, etc) + mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); if (mFirstPersonView && !mVanity.enabled) { return; } @@ -310,10 +307,7 @@ namespace MWRender delete mAnimation; mAnimation = anim; - mPlayerNode->setVisible( - mVanity.enabled || mPreviewMode || !mFirstPersonView, - false - ); + mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); } void Player::setHeight(float height) From 360f7bfac88a3d1346691eb8d6896b61125bf9ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 07:04:18 -0800 Subject: [PATCH 0177/1483] Apply animations to bones manually Couple reasons for this: * This paves the way for allowing animations specified in other skeletons to be applied to the character (NPCs and certain creatures can have multiple animation sources, but Ogre is incredibly strict when it comes to sharing animations between skeletons). * It will allow for entities to be animated based on the character's skeleton, without having to duplicate the mesh for each skeleton it can be used on. This doesn't impact Ogre's ability to efficiently deform skinned meshes, nor does it get in the way of hardware skinning. --- apps/openmw/mwrender/animation.cpp | 61 ++++++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 778efc8132..03bc92e96d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -94,24 +94,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } - // Reset initial state of bones that are animated, so the animation correctly applies. - if(skelinst->getNumAnimations() > 0) - { - Ogre::Animation *anim = skelinst->getAnimation(0); - Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); - while(trackiter.hasMoreElements()) - { - const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); - if(!skelinst->hasBone(srcnode->getName())) - continue; - - Ogre::Bone *bone = skelinst->getBone(srcnode->getName()); - bone->setOrientation(Ogre::Quaternion::IDENTITY); - bone->setPosition(Ogre::Vector3::ZERO); - bone->setScale(Ogre::Vector3(1.0f)); - bone->setInitialState(); - } - } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). + boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); } } @@ -134,16 +122,39 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) } +void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) +{ + Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); + Ogre::Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator(); + while(tracks.hasMoreElements()) + { + Ogre::NodeAnimationTrack *track = tracks.getNext(); + const Ogre::String &targetname = track->getAssociatedNode()->getName(); + if(!skel->hasBone(targetname)) + continue; + Ogre::Bone *bone = skel->getBone(targetname); + bone->setOrientation(Ogre::Quaternion::IDENTITY); + bone->setPosition(Ogre::Vector3::ZERO); + bone->setScale(Ogre::Vector3::UNIT_SCALE); + track->applyToNode(bone, timeindex); + } + + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); +} + + Ogre::Vector3 Animation::updatePosition(float time) { + Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); mAnimState->setTimePosition(time); + applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) { - /* Update the animation and get the non-accumulation root's difference from the - * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + /* Get the non-accumulation root's difference from the last update. */ posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ @@ -159,6 +170,7 @@ void Animation::reset(const std::string &marker) while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; + Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); if(mNextKey != mCurrentKeys->end()) mAnimState->setTimePosition(mNextKey->first); else @@ -166,10 +178,10 @@ void Animation::reset(const std::string &marker) mNextKey = mCurrentKeys->begin(); mAnimState->setTimePosition(0.0f); } + applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } @@ -179,10 +191,7 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - if(mAnimState) - mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mAnimState->setEnabled(true); mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; @@ -197,6 +206,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo Ogre::Vector3 Animation::runAnimation(float timepassed) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; + timepassed *= mAnimSpeedMult; while(mAnimState && mPlaying && timepassed > 0.0f) { @@ -249,6 +259,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mController) mController->markerEvent(time, evt); } + return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5fa1bd85c7..c281551c7d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -35,6 +35,8 @@ protected: float mAnimSpeedMult; + void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); From 5c3a7f7d523192c95380f9ec92e51ea25eb09213 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 07:34:07 -0800 Subject: [PATCH 0178/1483] Avoid handling animation states We don't need them anymore --- apps/openmw/mwrender/animation.cpp | 41 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 4 ++- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 03bc92e96d..73780a7f03 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -25,8 +25,10 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) - , mAnimState(NULL) + , mCurrentAnim(NULL) + , mCurrentTime(0.0f) , mPlaying(false) + , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -106,7 +108,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model bool Animation::hasAnimation(const std::string &anim) { - return mEntityList.mSkelBase && mEntityList.mSkelBase->hasAnimationState(anim); + return mEntityList.mSkelBase && mEntityList.mSkelBase->getSkeleton()->hasAnimation(anim); } @@ -147,9 +149,11 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk Ogre::Vector3 Animation::updatePosition(float time) { - Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); - mAnimState->setTimePosition(time); - applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); + if(mLooping) + mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); + else + mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); + applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) @@ -170,15 +174,14 @@ void Animation::reset(const std::string &marker) while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; - Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); if(mNextKey != mCurrentKeys->end()) - mAnimState->setTimePosition(mNextKey->first); + mCurrentTime = mNextKey->first; else { mNextKey = mCurrentKeys->begin(); - mAnimState->setTimePosition(0.0f); + mCurrentTime = 0.0f; } - applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); + applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); if(mNonAccumRoot) { @@ -191,12 +194,12 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mAnimState->setLoop(loop); - + mCurrentAnim = mEntityList.mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + reset(start); mPlaying = true; + mLooping = loop; } catch(std::exception &e) { std::cerr<< e.what() < 0.0f) + while(mCurrentAnim && mPlaying && timepassed > 0.0f) { - float targetTime = mAnimState->getTimePosition() + timepassed; + float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (mAnimState->getLoop() || mAnimState->getLength() >= targetTime); + mPlaying = (mLooping || mCurrentAnim->getLength() >= targetTime); break; } @@ -232,20 +235,20 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "loop stop") { - if(mAnimState->getLoop()) + if(mLooping) { reset("loop start"); - if(mAnimState->getTimePosition() >= time) + if(mCurrentTime >= time) break; } continue; } if(evt == "stop") { - if(mAnimState->getLoop()) + if(mLooping) { reset("loop start"); - if(mAnimState->getTimePosition() >= time) + if(mCurrentTime >= time) break; } else diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c281551c7d..886d967ab7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -30,8 +30,10 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; - Ogre::AnimationState *mAnimState; + Ogre::Animation *mCurrentAnim; + float mCurrentTime; bool mPlaying; + bool mLooping; float mAnimSpeedMult; From b6354c6282785feba4106a919242c491dcea3380 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 09:29:16 -0800 Subject: [PATCH 0179/1483] Don't share skeleton instances between bounded parts on an NPC However, a skeleton instance will still be shared between entities in an entity list. --- apps/openmw/mwrender/animation.cpp | 15 +++++++++++++++ apps/openmw/mwrender/animation.hpp | 5 +++++ apps/openmw/mwrender/npcanimation.cpp | 26 +++++++++++++++++++++++++- components/nifogre/ogre_nif_loader.cpp | 5 ++--- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 73780a7f03..b63de2f166 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -146,6 +146,21 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } +void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel) +{ + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.getNext(); + if(!skelsrc->hasBone(bone->getName())) + continue; + Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); + bone->setOrientation(srcbone->getOrientation()); + bone->setPosition(srcbone->getPosition()); + bone->setScale(srcbone->getScale()); + } +} + Ogre::Vector3 Animation::updatePosition(float time) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 886d967ab7..60e524d280 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -37,8 +37,13 @@ protected: float mAnimSpeedMult; + /* Applies the given animation to the given skeleton instance, using the specified time. */ void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); + /* Updates a skeleton instance so that all bones matching the source skeleton (based on + * bone names) are positioned identically. */ + void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 432a2f5260..03fda89820 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -305,6 +305,21 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); } + if(entities.mSkelBase) + { + Ogre::AnimationStateSet *aset = entities.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) + { + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); + } + Ogre::SkeletonInstance *skelinst = entities.mSkelBase->getSkeleton(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); + } return entities; } @@ -317,7 +332,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) } mTimeToChange += timepassed; - return Animation::runAnimation(timepassed); + Ogre::Vector3 ret = Animation::runAnimation(timepassed); + const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); + for(size_t i = 0;i < sPartListSize;i++) + { + Ogre::Entity *ent = (this->*sPartList[i].ents).mSkelBase; + if(!ent) continue; + updateSkeletonInstance(skelsrc, ent->getSkeleton()); + ent->getAllAnimationStates()->_notifyDirty(); + } + return ret; } void NpcAnimation::removeEntities(NifOgre::EntityList &entities) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index d1bf803f13..5444c803b8 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1228,19 +1228,18 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(entitylist.mSkelBase) { - entitylist.mSkelBase->shareSkeletonInstanceWith(parent); 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); + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) { - Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(bonename, entity); tag->setScale(scale); } } From f029a9011aea60f54ad63617cb9eaf3613ee72b0 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sun, 27 Jan 2013 22:40:38 +0100 Subject: [PATCH 0180/1483] Move datafilespage to shared space. --- apps/launcher/CMakeLists.txt | 33 ------------------- apps/launcher/graphicspage.cpp | 3 +- apps/launcher/maindialog.cpp | 3 +- cmake/OpenMWMacros.cmake | 16 +++++++++ components/CMakeLists.txt | 12 ++++++- .../file_order_list}/datafilespage.cpp | 0 .../file_order_list}/datafilespage.hpp | 0 .../file_order_list}/model/datafilesmodel.cpp | 0 .../file_order_list}/model/datafilesmodel.hpp | 0 .../file_order_list}/model/esm/esmfile.cpp | 0 .../file_order_list}/model/esm/esmfile.hpp | 0 .../file_order_list}/model/modelitem.cpp | 0 .../file_order_list}/model/modelitem.hpp | 0 .../file_order_list}/utils/filedialog.cpp | 0 .../file_order_list}/utils/filedialog.hpp | 0 .../file_order_list}/utils/lineedit.cpp | 0 .../file_order_list}/utils/lineedit.hpp | 0 .../file_order_list}/utils/naturalsort.cpp | 0 .../file_order_list}/utils/naturalsort.hpp | 0 .../utils/profilescombobox.cpp | 0 .../utils/profilescombobox.hpp | 0 .../utils/textinputdialog.cpp | 0 .../utils/textinputdialog.hpp | 0 23 files changed, 30 insertions(+), 37 deletions(-) rename {apps/launcher => components/file_order_list}/datafilespage.cpp (100%) rename {apps/launcher => components/file_order_list}/datafilespage.hpp (100%) rename {apps/launcher => components/file_order_list}/model/datafilesmodel.cpp (100%) rename {apps/launcher => components/file_order_list}/model/datafilesmodel.hpp (100%) rename {apps/launcher => components/file_order_list}/model/esm/esmfile.cpp (100%) rename {apps/launcher => components/file_order_list}/model/esm/esmfile.hpp (100%) rename {apps/launcher => components/file_order_list}/model/modelitem.cpp (100%) rename {apps/launcher => components/file_order_list}/model/modelitem.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/filedialog.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/filedialog.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/lineedit.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/lineedit.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/naturalsort.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/naturalsort.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/profilescombobox.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/profilescombobox.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/textinputdialog.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/textinputdialog.hpp (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 09beaf59de..73efb9ee51 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -1,56 +1,23 @@ set(LAUNCHER - datafilespage.cpp graphicspage.cpp main.cpp maindialog.cpp playpage.cpp - model/datafilesmodel.cpp - model/modelitem.cpp - model/esm/esmfile.cpp - - utils/filedialog.cpp - utils/naturalsort.cpp - utils/lineedit.cpp - utils/profilescombobox.cpp - utils/textinputdialog.cpp - launcher.rc ) set(LAUNCHER_HEADER - datafilespage.hpp graphicspage.hpp maindialog.hpp playpage.hpp - - model/datafilesmodel.hpp - model/modelitem.hpp - model/esm/esmfile.hpp - - utils/lineedit.hpp - utils/filedialog.hpp - utils/naturalsort.hpp - utils/profilescombobox.hpp - utils/textinputdialog.hpp - ) # Headers that must be pre-processed set(LAUNCHER_HEADER_MOC - datafilespage.hpp graphicspage.hpp maindialog.hpp playpage.hpp - - model/datafilesmodel.hpp - model/modelitem.hpp - model/esm/esmfile.hpp - - utils/lineedit.hpp - utils/filedialog.hpp - utils/profilescombobox.hpp - utils/textinputdialog.hpp ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2c4f3430c5..e69a8c2077 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -8,8 +8,7 @@ #include #include #include - -#include "utils/naturalsort.hpp" +#include #include "graphicspage.hpp" diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 674ccdf672..7eb31e76bb 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,9 +1,10 @@ #include +#include + #include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" -#include "datafilespage.hpp" MainDialog::MainDialog() { diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index e6f45fdb1f..398363667b 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -23,6 +23,22 @@ endforeach (u) source_group ("components\\${dir}" FILES ${files}) endmacro (add_component_dir) +macro (add_component_qt_dir dir) +set (files) +foreach (u ${ARGN}) +file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +foreach (f ${ALL}) +list (APPEND files "${f}") +list (APPEND COMPONENT_FILES "${f}") +endforeach (f) +file (GLOB MOC_H ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.hpp") +foreach (fi ${MOC_H}) +list (APPEND COMPONENT_MOC_FILES "${fi}") +endforeach (fi) +endforeach (u) +source_group ("components\\${dir}" FILES ${files}) +endmacro (add_component_qt_dir) + macro (copy_all_files source_dir destination_dir files) foreach (f ${files}) get_filename_component(filename ${f} NAME) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3da09ecb8f..a6812dbb30 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -66,9 +66,19 @@ add_component_dir (translation translation ) +add_component_qt_dir (file_order_list + datafilespage model/modelitem model/datafilesmodel model/esm/esmfile + utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort + ) + +find_package(Qt4 COMPONENTS QtCore QtGUI REQUIRED) +include(${QT_USE_FILE}) + +QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + include_directories(${BULLET_INCLUDE_DIRS}) -add_library(components STATIC ${COMPONENT_FILES}) +add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS}) target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) diff --git a/apps/launcher/datafilespage.cpp b/components/file_order_list/datafilespage.cpp similarity index 100% rename from apps/launcher/datafilespage.cpp rename to components/file_order_list/datafilespage.cpp diff --git a/apps/launcher/datafilespage.hpp b/components/file_order_list/datafilespage.hpp similarity index 100% rename from apps/launcher/datafilespage.hpp rename to components/file_order_list/datafilespage.hpp diff --git a/apps/launcher/model/datafilesmodel.cpp b/components/file_order_list/model/datafilesmodel.cpp similarity index 100% rename from apps/launcher/model/datafilesmodel.cpp rename to components/file_order_list/model/datafilesmodel.cpp diff --git a/apps/launcher/model/datafilesmodel.hpp b/components/file_order_list/model/datafilesmodel.hpp similarity index 100% rename from apps/launcher/model/datafilesmodel.hpp rename to components/file_order_list/model/datafilesmodel.hpp diff --git a/apps/launcher/model/esm/esmfile.cpp b/components/file_order_list/model/esm/esmfile.cpp similarity index 100% rename from apps/launcher/model/esm/esmfile.cpp rename to components/file_order_list/model/esm/esmfile.cpp diff --git a/apps/launcher/model/esm/esmfile.hpp b/components/file_order_list/model/esm/esmfile.hpp similarity index 100% rename from apps/launcher/model/esm/esmfile.hpp rename to components/file_order_list/model/esm/esmfile.hpp diff --git a/apps/launcher/model/modelitem.cpp b/components/file_order_list/model/modelitem.cpp similarity index 100% rename from apps/launcher/model/modelitem.cpp rename to components/file_order_list/model/modelitem.cpp diff --git a/apps/launcher/model/modelitem.hpp b/components/file_order_list/model/modelitem.hpp similarity index 100% rename from apps/launcher/model/modelitem.hpp rename to components/file_order_list/model/modelitem.hpp diff --git a/apps/launcher/utils/filedialog.cpp b/components/file_order_list/utils/filedialog.cpp similarity index 100% rename from apps/launcher/utils/filedialog.cpp rename to components/file_order_list/utils/filedialog.cpp diff --git a/apps/launcher/utils/filedialog.hpp b/components/file_order_list/utils/filedialog.hpp similarity index 100% rename from apps/launcher/utils/filedialog.hpp rename to components/file_order_list/utils/filedialog.hpp diff --git a/apps/launcher/utils/lineedit.cpp b/components/file_order_list/utils/lineedit.cpp similarity index 100% rename from apps/launcher/utils/lineedit.cpp rename to components/file_order_list/utils/lineedit.cpp diff --git a/apps/launcher/utils/lineedit.hpp b/components/file_order_list/utils/lineedit.hpp similarity index 100% rename from apps/launcher/utils/lineedit.hpp rename to components/file_order_list/utils/lineedit.hpp diff --git a/apps/launcher/utils/naturalsort.cpp b/components/file_order_list/utils/naturalsort.cpp similarity index 100% rename from apps/launcher/utils/naturalsort.cpp rename to components/file_order_list/utils/naturalsort.cpp diff --git a/apps/launcher/utils/naturalsort.hpp b/components/file_order_list/utils/naturalsort.hpp similarity index 100% rename from apps/launcher/utils/naturalsort.hpp rename to components/file_order_list/utils/naturalsort.hpp diff --git a/apps/launcher/utils/profilescombobox.cpp b/components/file_order_list/utils/profilescombobox.cpp similarity index 100% rename from apps/launcher/utils/profilescombobox.cpp rename to components/file_order_list/utils/profilescombobox.cpp diff --git a/apps/launcher/utils/profilescombobox.hpp b/components/file_order_list/utils/profilescombobox.hpp similarity index 100% rename from apps/launcher/utils/profilescombobox.hpp rename to components/file_order_list/utils/profilescombobox.hpp diff --git a/apps/launcher/utils/textinputdialog.cpp b/components/file_order_list/utils/textinputdialog.cpp similarity index 100% rename from apps/launcher/utils/textinputdialog.cpp rename to components/file_order_list/utils/textinputdialog.cpp diff --git a/apps/launcher/utils/textinputdialog.hpp b/components/file_order_list/utils/textinputdialog.hpp similarity index 100% rename from apps/launcher/utils/textinputdialog.hpp rename to components/file_order_list/utils/textinputdialog.hpp From ac62dd050d31066ed1c40655bd167e22ff5d2b81 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Wed, 30 Jan 2013 21:08:27 +0100 Subject: [PATCH 0181/1483] Rename datafilespage to datafileslist --- apps/launcher/maindialog.cpp | 20 +++++----- apps/launcher/maindialog.hpp | 4 +- components/CMakeLists.txt | 2 +- .../{datafilespage.cpp => datafileslist.cpp} | 38 +++++++++---------- .../{datafilespage.hpp => datafileslist.hpp} | 8 ++-- 5 files changed, 36 insertions(+), 36 deletions(-) rename components/file_order_list/{datafilespage.cpp => datafileslist.cpp} (97%) rename components/file_order_list/{datafilespage.hpp => datafileslist.hpp} (92%) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 7eb31e76bb..43b8f317ab 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include "maindialog.hpp" #include "playpage.hpp" @@ -124,16 +124,16 @@ void MainDialog::createPages() { mPlayPage = new PlayPage(this); mGraphicsPage = new GraphicsPage(mCfgMgr, this); - mDataFilesPage = new DataFilesPage(mCfgMgr, this); + mDataFilesList = new DataFilesList(mCfgMgr, this); // Set the combobox of the play page to imitate the combobox on the datafilespage - mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); - mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); + mPlayPage->mProfilesComboBox->setModel(mDataFilesList->mProfilesComboBox->model()); + mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesList->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget mPagesWidget->addWidget(mPlayPage); mPagesWidget->addWidget(mGraphicsPage); - mPagesWidget->addWidget(mDataFilesPage); + mPagesWidget->addWidget(mDataFilesList); // Select the first page mIconWidget->setCurrentItem(mIconWidget->item(0), QItemSelectionModel::Select); @@ -142,9 +142,9 @@ void MainDialog::createPages() connect(mPlayPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), - mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); + mDataFilesList->mProfilesComboBox, SLOT(setCurrentIndex(int))); - connect(mDataFilesPage->mProfilesComboBox, + connect(mDataFilesList->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); @@ -190,7 +190,7 @@ bool MainDialog::setup() } // Setup the Data Files page - if (!mDataFilesPage->setupDataFiles()) { + if (!mDataFilesList->setupDataFiles()) { return false; } @@ -208,7 +208,7 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) void MainDialog::closeEvent(QCloseEvent *event) { // Now write all config files - mDataFilesPage->writeConfig(); + mDataFilesList->writeConfig(); mGraphicsPage->writeConfig(); // Save user settings @@ -221,7 +221,7 @@ void MainDialog::closeEvent(QCloseEvent *event) void MainDialog::play() { // First do a write of all the configs, just to be sure - mDataFilesPage->writeConfig(); + mDataFilesList->writeConfig(); mGraphicsPage->writeConfig(); // Save user settings diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index bf98011cc4..5a39c11a99 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -15,7 +15,7 @@ class QString; class PlayPage; class GraphicsPage; -class DataFilesPage; +class DataFilesList; class MainDialog : public QMainWindow { @@ -39,7 +39,7 @@ private: PlayPage *mPlayPage; GraphicsPage *mGraphicsPage; - DataFilesPage *mDataFilesPage; + DataFilesList *mDataFilesList; Files::ConfigurationManager mCfgMgr; Settings::Manager mSettings; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a6812dbb30..3798f66b7a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -67,7 +67,7 @@ add_component_dir (translation ) add_component_qt_dir (file_order_list - datafilespage model/modelitem model/datafilesmodel model/esm/esmfile + datafileslist model/modelitem model/datafilesmodel model/esm/esmfile utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort ) diff --git a/components/file_order_list/datafilespage.cpp b/components/file_order_list/datafileslist.cpp similarity index 97% rename from components/file_order_list/datafilespage.cpp rename to components/file_order_list/datafileslist.cpp index 6b0539c1dd..bf4f8cb861 100644 --- a/components/file_order_list/datafilespage.cpp +++ b/components/file_order_list/datafileslist.cpp @@ -12,7 +12,7 @@ #include "utils/naturalsort.hpp" #include "utils/textinputdialog.hpp" -#include "datafilespage.hpp" +#include "datafileslist.hpp" #include /** @@ -46,7 +46,7 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) return index1.row() <= index2.row(); } -DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) +DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) : QWidget(parent) , mCfgMgr(cfg) { @@ -180,7 +180,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) setupConfig(); } -void DataFilesPage::createActions() +void DataFilesList::createActions() { // Refresh the plugins QAction *refreshAction = new QAction(tr("Refresh"), this); @@ -218,7 +218,7 @@ void DataFilesPage::createActions() } -void DataFilesPage::setupConfig() +void DataFilesList::setupConfig() { // Open our config file QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); @@ -265,7 +265,7 @@ void DataFilesPage::setupConfig() } -void DataFilesPage::readConfig() +void DataFilesList::readConfig() { // Don't read the config if no masters are found if (mMastersModel->rowCount() < 1) @@ -340,7 +340,7 @@ void DataFilesPage::readConfig() } -bool DataFilesPage::showDataFilesWarning() +bool DataFilesList::showDataFilesWarning() { QMessageBox msgBox; @@ -381,7 +381,7 @@ bool DataFilesPage::showDataFilesWarning() return true; } -bool DataFilesPage::setupDataFiles() +bool DataFilesList::setupDataFiles() { // We use the Configuration Manager to retrieve the configuration values boost::program_options::variables_map variables; @@ -451,7 +451,7 @@ bool DataFilesPage::setupDataFiles() return true; } -void DataFilesPage::writeConfig(QString profile) +void DataFilesList::writeConfig(QString profile) { // Don't overwrite the config if no masters are found if (mMastersModel->rowCount() < 1) @@ -606,7 +606,7 @@ void DataFilesPage::writeConfig(QString profile) } -void DataFilesPage::newProfile() +void DataFilesList::newProfile() { if (mNewProfileDialog->exec() == QDialog::Accepted) { @@ -621,7 +621,7 @@ void DataFilesPage::newProfile() } } -void DataFilesPage::updateOkButton(const QString &text) +void DataFilesList::updateOkButton(const QString &text) { if (text.isEmpty()) { mNewProfileDialog->setOkButtonEnabled(false); @@ -633,7 +633,7 @@ void DataFilesPage::updateOkButton(const QString &text) : mNewProfileDialog->setOkButtonEnabled(false); } -void DataFilesPage::deleteProfile() +void DataFilesList::deleteProfile() { QString profile = mProfilesComboBox->currentText(); @@ -670,7 +670,7 @@ void DataFilesPage::deleteProfile() } } -void DataFilesPage::check() +void DataFilesList::check() { // Check the current selection if (!mPluginsTable->selectionModel()->hasSelection()) { @@ -690,7 +690,7 @@ void DataFilesPage::check() } } -void DataFilesPage::uncheck() +void DataFilesList::uncheck() { // uncheck the current selection if (!mPluginsTable->selectionModel()->hasSelection()) { @@ -710,7 +710,7 @@ void DataFilesPage::uncheck() } } -void DataFilesPage::refresh() +void DataFilesList::refresh() { mPluginsModel->sort(0); @@ -722,7 +722,7 @@ void DataFilesPage::refresh() } -void DataFilesPage::setCheckState(QModelIndex index) +void DataFilesList::setCheckState(QModelIndex index) { if (!index.isValid()) return; @@ -751,13 +751,13 @@ void DataFilesPage::setCheckState(QModelIndex index) } -void DataFilesPage::filterChanged(const QString filter) +void DataFilesList::filterChanged(const QString filter) { QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); mPluginsProxyModel->setFilterRegExp(regExp); } -void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) +void DataFilesList::profileChanged(const QString &previous, const QString ¤t) { qDebug() << "Profile is changed from: " << previous << " to " << current; // Prevent the deletion of the default profile @@ -785,7 +785,7 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre readConfig(); } -void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) +void DataFilesList::profileRenamed(const QString &previous, const QString ¤t) { if (previous.isEmpty()) return; @@ -815,7 +815,7 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre readConfig(); } -void DataFilesPage::showContextMenu(const QPoint &point) +void DataFilesList::showContextMenu(const QPoint &point) { // Make sure there are plugins in the view if (!mPluginsTable->selectionModel()->hasSelection()) { diff --git a/components/file_order_list/datafilespage.hpp b/components/file_order_list/datafileslist.hpp similarity index 92% rename from components/file_order_list/datafilespage.hpp rename to components/file_order_list/datafileslist.hpp index 13668ec30e..7bb6605ab0 100644 --- a/components/file_order_list/datafilespage.hpp +++ b/components/file_order_list/datafileslist.hpp @@ -1,5 +1,5 @@ -#ifndef DATAFILESPAGE_H -#define DATAFILESPAGE_H +#ifndef DATAFILESLIST_H +#define DATAFILESLIST_H #include #include @@ -20,12 +20,12 @@ class TextInputDialog; namespace Files { struct ConfigurationManager; } -class DataFilesPage : public QWidget +class DataFilesList : public QWidget { Q_OBJECT public: - DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); + DataFilesList(Files::ConfigurationManager& cfg, QWidget *parent = 0); ProfilesComboBox *mProfilesComboBox; From dc91211b12f7fa6b4b9c0bdd505f2618ed8125fc Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 00:21:04 +0000 Subject: [PATCH 0182/1483] Fixed Small bug where scripts were being removed when they shouldn't be. Scripts should only be removed when the item is being moved to another cell, otherwise they should remain active. --- apps/openmw/mwworld/worldimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 24d139b377..ddcace338a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -694,10 +694,11 @@ namespace MWWorld bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; - removeContainerScripts(ptr); if (*currCell != newCell) { + removeContainerScripts(ptr); + if (isPlayer) if (!newCell.isExterior()) changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos); From 09f9557ecb516a0a4d0d3db5e0364712a0c21b8a Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 00:34:16 +0000 Subject: [PATCH 0183/1483] Implemented OnPCEquip special variable --- apps/openmw/mwworld/actionequip.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 60260a812b..c519a3ee54 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -3,6 +3,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/scriptmanager.hpp" + +#include #include "inventorystore.hpp" #include "player.hpp" @@ -35,6 +38,8 @@ namespace MWWorld std::string npcRace = actor.get()->mBase->mRace; + bool equipped = false; + // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) @@ -91,6 +96,7 @@ namespace MWWorld if (slot == --slots.first.end()) { invStore.equip(*slot, it); + equipped = true; break; } @@ -98,8 +104,16 @@ namespace MWWorld { // slot is not occupied invStore.equip(*slot, it); + equipped = true; break; } } + + /* Set OnPCEquip Variable on item's script, if it has a script with that variable declared */ + if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && MWWorld::Class::get(*it).getScript(*it) != ""){ + int index = MWBase::Environment::get().getScriptManager()->getLocals(MWWorld::Class::get(*it).getScript(*it)).getIndex("onpcequip"); + if(index != -1) + (*it).mRefData->getLocals().mShorts.at (index) = 1; + } } } From d6f923f2743afd4bd781e5a31bc5f897f3f18785 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 22:28:18 -0800 Subject: [PATCH 0184/1483] Use a child scene node for the accumulation root --- apps/openmw/mwrender/animation.cpp | 5 ++--- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b63de2f166..b811040676 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node; + mInsert = node->createChildSceneNode(); assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,8 +76,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); + mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 60e524d280..165a6525c3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Bone *mAccumRoot; + Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From c6a9ea50076765f26eee02616a9531ff95815133 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 22:37:39 -0800 Subject: [PATCH 0185/1483] Use the skeleton as defined in the NIF model The avoids having to duplicate models that get attached to different character skeletons. --- components/nifogre/ogre_nif_loader.cpp | 59 ++++++++++++++------------ components/nifogre/ogre_nif_loader.hpp | 2 +- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5444c803b8..9c9fd3b22f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -754,7 +754,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mName; std::string mGroup; size_t mShapeIndex; - std::string mSkelName; std::string mMaterialName; std::string mShapeName; @@ -782,11 +781,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be // explicitly attached later. - mesh->setSkeletonName(mSkelName); + 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(mSkelName); + skel = skelMgr->getByName(mName); // 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 @@ -823,22 +822,26 @@ class NIFMeshLoader : Ogre::ManualResourceLoader srcVerts = newVerts; srcNorms = newNorms; } - else if(mSkelName.length() == 0) + else { - // 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::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(skelMgr->getByName(mName).isNull()) { - 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]); + // 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]); + } } } @@ -998,8 +1001,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader public: NIFMeshLoader() { } - NIFMeshLoader(const std::string &name, const std::string &group, const std::string skelName) - : mName(name), mGroup(group), mShapeIndex(~(size_t)0), mSkelName(skelName) + NIFMeshLoader(const std::string &name, const std::string &group) + : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } virtual void loadResource(Ogre::Resource *resource) @@ -1010,7 +1013,9 @@ public: Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); if(mShapeIndex >= nif->numRecords()) { - mesh->setSkeletonName(mSkelName); + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(!skelMgr->getByName(mName).isNull()) + mesh->setSkeletonName(mName); return; } @@ -1061,8 +1066,6 @@ public: std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); if(mShapeName.length() > 0) fullname += "@shape="+mShapeName; - if(mSkelName.length() > 0 && mName != mSkelName) - fullname += "@skel="+mSkelName; Misc::StringUtils::toLower(fullname); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); @@ -1105,13 +1108,13 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshInfoMap; static MeshInfoMap sMeshInfoMap; -MeshInfoList Loader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList Loader::load(const std::string &name, const std::string &group) { - MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); + MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name); if(meshiter != sMeshInfoMap.end()) return meshiter->second; - MeshInfoList &meshes = sMeshInfoMap[name+"@skel="+skelName]; + MeshInfoList &meshes = sMeshInfoMap[name]; Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); if(nif.numRecords() < 1) @@ -1139,7 +1142,7 @@ MeshInfoList Loader::load(const std::string &name, const std::string &skelName, hasSkel = skelldr.createSkeleton(name, group, node); } - NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); + NIFMeshLoader meshldr(name, group); meshldr.createMeshes(node, meshes); return meshes; @@ -1150,7 +1153,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, name, group); + MeshInfoList meshes = load(name, group); if(meshes.size() == 0) return entitylist; @@ -1199,7 +1202,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, parent->getMesh()->getSkeletonName(), group); + MeshInfoList 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 f87d7d3c21..13a76d4721 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -66,7 +66,7 @@ typedef std::vector MeshInfoList; class Loader { - static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); + static MeshInfoList load(const std::string &name, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From 0fc5ee5149534facb779c4eed37f6f8f565856c2 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 17:46:16 +0000 Subject: [PATCH 0186/1483] allow OnPCEquip special variable to be of any type --- apps/openmw/mwworld/actionequip.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index c519a3ee54..2b238ead99 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -109,11 +109,28 @@ namespace MWWorld } } - /* Set OnPCEquip Variable on item's script, if it has a script with that variable declared */ - if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && MWWorld::Class::get(*it).getScript(*it) != ""){ - int index = MWBase::Environment::get().getScriptManager()->getLocals(MWWorld::Class::get(*it).getScript(*it)).getIndex("onpcequip"); + std::string script = MWWorld::Class::get(*it).getScript(*it); + + /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ + if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") + { + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex("onpcequip"); + char type = locals.getType("onpcequip"); if(index != -1) - (*it).mRefData->getLocals().mShorts.at (index) = 1; + { + switch(type) + { + case 's': + (*it).mRefData->getLocals().mShorts.at (index) = 1; break; + + case 'l': + (*it).mRefData->getLocals().mLongs.at (index) = 1; break; + + case 'f': + (*it).mRefData->getLocals().mFloats.at (index) = 1.0; break; + } + } } } } From 9ad08520fd766e45514e479a2f8ff866be3995b6 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 18:45:32 +0000 Subject: [PATCH 0187/1483] Implemented OnPCDrop special variable Scripts are responsible for resetting to 0, as investigation showed that is how vanilla handled it. --- apps/openmw/mwworld/worldimp.cpp | 44 ++++++++++++++++++++++++++++---- apps/openmw/mwworld/worldimp.hpp | 5 ++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ddcace338a..0c8027975b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2,11 +2,13 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" @@ -1271,6 +1273,33 @@ namespace MWWorld mRendering->toggleWater(); } + void World::PCDropped (const Ptr& item) + { + std::string script = MWWorld::Class::get(item).getScript(item); + + /* Set OnPCDrop Variable on item's script, if it has a script with that variable declared */ + if(script != "") + { + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex("onpcdrop"); + char type = locals.getType("onpcdrop"); + if(index != -1) + { + switch(type) + { + case 's': + item.mRefData->getLocals().mShorts.at (index) = 1; break; + + case 'l': + item.mRefData->getLocals().mLongs.at (index) = 1; break; + + case 'f': + item.mRefData->getLocals().mFloats.at (index) = 1.0; break; + } + } + } + } + bool World::placeObject (const Ptr& object, float cursorX, float cursorY) { std::pair result = mPhysics->castRay(cursorX, cursorY); @@ -1293,9 +1322,10 @@ namespace MWWorld pos.pos[1] = -result.second[2]; pos.pos[2] = result.second[1]; - copyObjectToCell(object, *cell, pos); + Ptr dropped = copyObjectToCell(object, *cell, pos); + PCDropped(dropped); object.getRefData().setCount(0); - + return true; } @@ -1310,8 +1340,8 @@ namespace MWWorld return true; } - void - World::copyObjectToCell(const Ptr &object, CellStore &cell, const ESM::Position &pos) + + Ptr World::copyObjectToCell(const Ptr &object, CellStore &cell, const ESM::Position &pos) { /// \todo add searching correct cell for position specified MWWorld::Ptr dropped = @@ -1335,6 +1365,8 @@ namespace MWWorld } addContainerScripts(dropped, &cell); } + + return dropped; } void World::dropObjectOnGround (const Ptr& actor, const Ptr& object) @@ -1355,7 +1387,9 @@ namespace MWWorld mPhysics->castRay(orig, dir, len); pos.pos[2] = hit.second.z; - copyObjectToCell(object, *cell, pos); + Ptr dropped = copyObjectToCell(object, *cell, pos); + if(actor == mPlayer->getPlayer()) // Only call if dropped by player + PCDropped(dropped); object.getRefData().setCount(0); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index fa5b41038d..e8efb6a670 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -91,8 +91,8 @@ namespace MWWorld bool moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return true if the active cell (cell player is in) changed - virtual void - copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos); + + Ptr copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos); void updateWindowManager (); void performUpdateSceneQueries (); @@ -107,6 +107,7 @@ namespace MWWorld void removeContainerScripts(const Ptr& reference); void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell); + void PCDropped (const Ptr& item); public: From 0f58e03343e3d3db1da04398367a5e0704fd7a91 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 19:04:39 +0000 Subject: [PATCH 0188/1483] Unequipping items will reset OnPCEquip variable --- apps/openmw/mwgui/inventorywindow.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5390f1602e..ebbd69d80b 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -7,10 +7,13 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -240,6 +243,29 @@ namespace MWGui if (it != invStore.end() && *it == item) { invStore.equip(slot, invStore.end()); + std::string script = MWWorld::Class::get(*it).getScript(*it); + + /* Unset OnPCEquip Variable on item's script, if it has a script with that variable declared */ + if(script != "") + { + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex("onpcequip"); + char type = locals.getType("onpcequip"); + if(index != -1) + { + switch(type) + { + case 's': + (*it).mRefData->getLocals().mShorts.at (index) = 0; break; + + case 'l': + (*it).mRefData->getLocals().mLongs.at (index) = 0; break; + + case 'f': + (*it).mRefData->getLocals().mFloats.at (index) = 0.0; break; + } + } + } return; } } From 492482de7f98091a90bff0fa4471475ae281dfc4 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Fri, 1 Feb 2013 00:42:03 +0100 Subject: [PATCH 0189/1483] Add "open" option in opencs. --- apps/opencs/CMakeLists.txt | 4 +-- apps/opencs/view/doc/view.cpp | 29 ++++++++++++++++++- apps/opencs/view/doc/view.hpp | 5 ++++ components/file_order_list/datafileslist.cpp | 16 ++++++++++ components/file_order_list/datafileslist.hpp | 1 + .../file_order_list/model/datafilesmodel.cpp | 20 +++++++++++++ .../file_order_list/model/datafilesmodel.hpp | 1 + 7 files changed, 73 insertions(+), 3 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index abbc953ca4..68b22c10ef 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -17,7 +17,7 @@ set (OPENCS_SRC view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp view/world/dialoguesubview.cpp - view/tools/reportsubview.cpp view/tools/subviews.cpp + view/tools/reportsubview.cpp view/tools/subviews.cpp view/tools/opendialog.cpp ) set (OPENCS_HDR @@ -38,7 +38,7 @@ set (OPENCS_HDR view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp view/world/dialoguesubview.hpp - view/tools/reportsubview.hpp view/tools/subviews.hpp + view/tools/reportsubview.hpp view/tools/subviews.hpp view/tools/opendialog.hpp ) set (OPENCS_US diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 13edb6e749..ebcb9aaa7f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -14,6 +14,8 @@ #include "../tools/subviews.hpp" +#include "../tools/opendialog.hpp" + #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -31,6 +33,10 @@ void CSVDoc::View::setupFileMenu() QAction *new_ = new QAction (tr ("New"), this); connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); file->addAction (new_); + + mLoad = new QAction(tr ("&Load"), this); + connect (mLoad, SIGNAL (triggered()), this, SLOT (load())); + file->addAction (mLoad); mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); @@ -110,7 +116,7 @@ void CSVDoc::View::updateActions() } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) -: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) +: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), mOpenDialog(0) { setDockOptions (QMainWindow::AllowNestedDocks); @@ -205,6 +211,27 @@ void CSVDoc::View::save() mDocument->save(); } +void CSVDoc::View::load() +{ + if (!mOpenDialog) { + mOpenDialog = new OpenDialog(this); + connect(mOpenDialog, SIGNAL(accepted()), this, SLOT(loadNewFiles())); + } + + mOpenDialog->show(); + mOpenDialog->raise(); + mOpenDialog->activateWindow(); +} + +void CSVDoc::View::loadNewFiles() +{ + //FIXME close old files + std::vector paths; + mOpenDialog->getFileList(paths); + //FIXME load new files + +} + void CSVDoc::View::verify() { addSubView (mDocument->verify()); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index b1dedafe92..1822522033 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -9,6 +9,7 @@ #include "subviewfactory.hpp" class QAction; +class OpenDialog; namespace CSMDoc { @@ -36,10 +37,12 @@ namespace CSVDoc QAction *mUndo; QAction *mRedo; QAction *mSave; + QAction *mLoad; QAction *mVerify; std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; + OpenDialog * mOpenDialog; // not implemented View (const View&); @@ -92,6 +95,8 @@ namespace CSVDoc void newView(); + void load(); + void loadNewFiles(); void save(); void verify(); diff --git a/components/file_order_list/datafileslist.cpp b/components/file_order_list/datafileslist.cpp index bf4f8cb861..f346407a90 100644 --- a/components/file_order_list/datafileslist.cpp +++ b/components/file_order_list/datafileslist.cpp @@ -451,6 +451,22 @@ bool DataFilesList::setupDataFiles() return true; } +void DataFilesList::getSelectedFiles(std::vector& paths) +{ + QStringList masterPaths = mMastersModel->checkedItemsPaths(); + foreach (const QString &path, masterPaths) + { + paths.push_back(path.toStdString()); + cerr << path.toStdString() << endl; + } + QStringList pluginPaths = mPluginsModel->checkedItemsPaths(); + foreach (const QString &path, pluginPaths) + { + paths.push_back(path.toStdString()); + cerr << path.toStdString() << endl; + } +} + void DataFilesList::writeConfig(QString profile) { // Don't overwrite the config if no masters are found diff --git a/components/file_order_list/datafileslist.hpp b/components/file_order_list/datafileslist.hpp index 7bb6605ab0..7bdb5e0571 100644 --- a/components/file_order_list/datafileslist.hpp +++ b/components/file_order_list/datafileslist.hpp @@ -32,6 +32,7 @@ public: void writeConfig(QString profile = QString()); bool showDataFilesWarning(); bool setupDataFiles(); + void getSelectedFiles(std::vector& paths); public slots: void setCheckState(QModelIndex index); diff --git a/components/file_order_list/model/datafilesmodel.cpp b/components/file_order_list/model/datafilesmodel.cpp index e84dbe0acc..5bb1996791 100644 --- a/components/file_order_list/model/datafilesmodel.cpp +++ b/components/file_order_list/model/datafilesmodel.cpp @@ -292,6 +292,7 @@ void DataFilesModel::addMasters(const QString &path) EsmFile *file = new EsmFile(master); file->setDates(info.lastModified(), info.lastRead()); + file->setPath(info.absoluteFilePath()); // Add the master to the table if (findItem(master) == 0) @@ -427,6 +428,25 @@ QStringList DataFilesModel::checkedItems() return list; } +QStringList DataFilesModel::checkedItemsPaths() +{ + QStringList list; + + QList::ConstIterator it; + QList::ConstIterator itEnd = mFiles.constEnd(); + + int i = 0; + for (it = mFiles.constBegin(); it != itEnd; ++it) { + EsmFile *file = item(i); + ++i; + + if (mCheckStates[file->fileName()] == Qt::Checked && mAvailableFiles.contains(file->fileName())) + list << file->path(); + } + + return list; +} + void DataFilesModel::uncheckAll() { emit layoutAboutToBeChanged(); diff --git a/components/file_order_list/model/datafilesmodel.hpp b/components/file_order_list/model/datafilesmodel.hpp index 29a770a862..adc80eac2a 100644 --- a/components/file_order_list/model/datafilesmodel.hpp +++ b/components/file_order_list/model/datafilesmodel.hpp @@ -43,6 +43,7 @@ public: QStringList checkedItems(); QStringList uncheckedItems(); + QStringList checkedItemsPaths(); Qt::CheckState checkState(const QModelIndex &index); void setCheckState(const QModelIndex &index, Qt::CheckState state); From 376dfed15ba01cee8d24d122dfafc797a86fd303 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Feb 2013 08:50:32 -0800 Subject: [PATCH 0190/1483] Revert "Use a child scene node for the accumulation root" This reverts commit d6f923f2743afd4bd781e5a31bc5f897f3f18785. We don't need it for any of the NIFs we're currently handling. As long as there's no NIF files that would break it, we should require a stationary root if an animation wants to accumulate. If we must, a better idea may be to inject an extra bone into the skeleton instance and make that the accumulation root. --- apps/openmw/mwrender/animation.cpp | 5 +++-- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b811040676..b63de2f166 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node->createChildSceneNode(); + mInsert = node; assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,7 +76,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = mInsert; + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 165a6525c3..60e524d280 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Node *mAccumRoot; + Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From a461b282c15083e6987356a1643c7b8a5b4295a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Feb 2013 23:43:23 +0100 Subject: [PATCH 0191/1483] water ripples (experimental) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 +- apps/openmw/mwrender/ripplesimulation.cpp | 212 ++++++++++++++++++ apps/openmw/mwrender/ripplesimulation.hpp | 72 ++++++ apps/openmw/mwrender/water.cpp | 14 +- apps/openmw/mwrender/water.hpp | 5 +- extern/shiny/Main/Factory.cpp | 2 + files/CMakeLists.txt | 7 + files/materials/core.h | 4 + files/materials/quad.mat | 2 +- files/materials/quad.shaderset | 2 +- files/materials/water.mat | 8 +- files/materials/water.shader | 28 ++- files/materials/watersim.mat | 59 +++++ files/materials/watersim.shaderset | 31 +++ files/materials/watersim_addimpulse.shader | 12 + files/materials/watersim_common.h | 25 +++ files/materials/watersim_heightmap.shader | 42 ++++ .../materials/watersim_heighttonormal.shader | 27 +++ files/water/circle.png | Bin 0 -> 753 bytes 20 files changed, 545 insertions(+), 14 deletions(-) create mode 100644 apps/openmw/mwrender/ripplesimulation.cpp create mode 100644 apps/openmw/mwrender/ripplesimulation.hpp create mode 100644 files/materials/watersim.mat create mode 100644 files/materials/watersim.shaderset create mode 100644 files/materials/watersim_addimpulse.shader create mode 100644 files/materials/watersim_common.h create mode 100644 files/materials/watersim_heightmap.shader create mode 100644 files/materials/watersim_heighttonormal.shader create mode 100644 files/water/circle.png diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090c..2c49e848ec 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows - compositors characterpreview externalrendering globalmap videoplayer + compositors characterpreview externalrendering globalmap videoplayer ripplesimulation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ff26b087c1..3fed4d9944 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -386,7 +386,10 @@ void RenderingManager::update (float duration, bool paused) *world->getPlayer().getPlayer().getCell()->mCell, Ogre::Vector3(cam.x, -cam.z, cam.y)) ); - mWater->update(duration); + + // MW to ogre coordinates + orig = Ogre::Vector3(orig.x, orig.z, -orig.y); + mWater->update(duration, orig); } } diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp new file mode 100644 index 0000000000..6096c7ba34 --- /dev/null +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -0,0 +1,212 @@ +#include "ripplesimulation.hpp" + +#include +#include +#include +#include + +#include + +namespace MWRender +{ + + +RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) + : mMainSceneMgr(mainSceneManager), + mTime(0), + mCurrentFrameOffset(0,0), + mPreviousFrameOffset(0,0), + mRippleCenter(0,0), + mTextureSize(512), + mRippleAreaLength(1000), + mImpulseSize(20), + mTexelOffset(0,0) +{ + Ogre::AxisAlignedBox aabInf; + aabInf.setInfinite(); + + + mHeightToNormalMapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightToNormalMap"); + mHeightmapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightmapSimulation"); + + mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); + + mCamera = mSceneMgr->createCamera("RippleCamera"); + + mRectangle = new Ogre::Rectangle2D(true); + mRectangle->setBoundingBox(aabInf); + mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0, false); + Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + node->attachObject(mRectangle); + + mImpulse = new Ogre::Rectangle2D(true); + mImpulse->setCorners(-0.1, 0.1, 0.1, -0.1, false); + mImpulse->setBoundingBox(aabInf); + mImpulse->setMaterial("AddImpulse"); + Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + impulseNode->attachObject(mImpulse); + + float w=0.05; + for (int i=0; i<4; ++i) + { + Ogre::TexturePtr texture; + if (i != 3) + texture = Ogre::TextureManager::getSingleton().createManual("RippleHeight" + Ogre::StringConverter::toString(i), + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); + else + texture = Ogre::TextureManager::getSingleton().createManual("RippleNormal", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); + + + Ogre::RenderTexture* rt = texture->getBuffer()->getRenderTarget(); + rt->removeAllViewports(); + rt->addViewport(mCamera); + rt->setAutoUpdated(false); + rt->getViewport(0)->setClearEveryFrame(false); + + // debug overlay + Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true); + debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false); + w += 0.2; + debugOverlay->setBoundingBox(aabInf); + + Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode(); + debugNode->attachObject(debugOverlay); + + Ogre::MaterialPtr debugMaterial = Ogre::MaterialManager::getSingleton().create("RippleDebug" + Ogre::StringConverter::toString(i), + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + + if (i != 3) + debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleHeight" + Ogre::StringConverter::toString(i)); + else + debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleNormal"); + debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + + debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i)); + + mRenderTargets[i] = rt; + mTextures[i] = texture; + } + + sh::Factory::getInstance().setSharedParameter("rippleTextureSize", sh::makeProperty( + new sh::Vector4(1.0/512, 1.0/512, 512, 512))); + sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( + new sh::Vector3(0, 0, 0))); + sh::Factory::getInstance().setSharedParameter("rippleAreaLength", sh::makeProperty( + new sh::FloatValue(mRippleAreaLength))); + +} + +RippleSimulation::~RippleSimulation() +{ + delete mRectangle; + + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); +} + +void RippleSimulation::update(float dt, Ogre::Vector2 position) +{ + // try to keep 20 fps + mTime += dt; + + while (mTime >= 1/20.0) + { + mPreviousFrameOffset = mCurrentFrameOffset; + + mCurrentFrameOffset = position - mRippleCenter; + // add texel offsets from previous frame. + mCurrentFrameOffset += mTexelOffset; + + mTexelOffset = Ogre::Vector2(std::fmod(mCurrentFrameOffset.x, 1.0f/mTextureSize), + std::fmod(mCurrentFrameOffset.y, 1.0f/mTextureSize)); + + // now subtract new offset in order to snap to texels + mCurrentFrameOffset -= mTexelOffset; + + // texture coordinate space + mCurrentFrameOffset /= mRippleAreaLength; + + std::cout << "Offset " << mCurrentFrameOffset << std::endl; + + mRippleCenter = position; + + addImpulses(); + waterSimulation(); + heightMapToNormalMap(); + + swapHeightMaps(); + mTime -= 1/20.0; + } + + sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( + new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); +} + +void RippleSimulation::addImpulse(Ogre::Vector2 position) +{ + mImpulses.push(position); +} + +void RippleSimulation::addImpulses() +{ + mRectangle->setVisible(false); + mImpulse->setVisible(true); + + while (mImpulses.size()) + { + Ogre::Vector2 pos = mImpulses.front(); + pos -= mRippleCenter; + pos /= mRippleAreaLength; + float size = mImpulseSize / mRippleAreaLength; + mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); + mImpulses.pop(); + + mRenderTargets[1]->update(); + } + + mImpulse->setVisible(false); + mRectangle->setVisible(true); +} + +void RippleSimulation::waterSimulation() +{ + mRectangle->setMaterial("HeightmapSimulation"); + + sh::Factory::getInstance().setTextureAlias("Heightmap0", mTextures[0]->getName()); + sh::Factory::getInstance().setTextureAlias("Heightmap1", mTextures[1]->getName()); + + sh::Factory::getInstance().setSharedParameter("currentFrameOffset", sh::makeProperty( + new sh::Vector3(mCurrentFrameOffset.x, mCurrentFrameOffset.y, 0))); + sh::Factory::getInstance().setSharedParameter("previousFrameOffset", sh::makeProperty( + new sh::Vector3(mPreviousFrameOffset.x, mPreviousFrameOffset.y, 0))); + + mRenderTargets[2]->update(); +} + +void RippleSimulation::heightMapToNormalMap() +{ + mRectangle->setMaterial("HeightToNormalMap"); + + sh::Factory::getInstance().setTextureAlias("Heightmap2", mTextures[2]->getName()); + + mRenderTargets[TEX_NORMAL]->update(); +} + +void RippleSimulation::swapHeightMaps() +{ + // 0 -> 1 -> 2 to 2 -> 0 ->1 + Ogre::RenderTexture* tmp = mRenderTargets[0]; + Ogre::TexturePtr tmp2 = mTextures[0]; + + mRenderTargets[0] = mRenderTargets[1]; + mTextures[0] = mTextures[1]; + + mRenderTargets[1] = mRenderTargets[2]; + mTextures[1] = mTextures[2]; + + mRenderTargets[2] = tmp; + mTextures[2] = tmp2; +} + + +} diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp new file mode 100644 index 0000000000..6096fa866c --- /dev/null +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -0,0 +1,72 @@ +#ifndef RIPPLE_SIMULATION_H +#define RIPPLE_SIMULATION_H + +#include +#include +#include + +namespace Ogre +{ + class RenderTexture; + class Camera; + class SceneManager; + class Rectangle2D; +} + +namespace MWRender +{ + +class RippleSimulation +{ +public: + RippleSimulation(Ogre::SceneManager* mainSceneManager); + ~RippleSimulation(); + + void update(float dt, Ogre::Vector2 position); + + void addImpulse (Ogre::Vector2 position); + +private: + Ogre::RenderTexture* mRenderTargets[4]; + Ogre::TexturePtr mTextures[4]; + + int mTextureSize; + float mRippleAreaLength; + float mImpulseSize; + + Ogre::Camera* mCamera; + + // own scenemanager to render our simulation + Ogre::SceneManager* mSceneMgr; + Ogre::Rectangle2D* mRectangle; + + // scenemanager to create the debug overlays on + Ogre::SceneManager* mMainSceneMgr; + + Ogre::MaterialPtr mHeightmapMaterial; + Ogre::MaterialPtr mHeightToNormalMapMaterial; + + static const int TEX_NORMAL = 3; + + Ogre::Rectangle2D* mImpulse; + + std::queue mImpulses; + + void addImpulses(); + void heightMapToNormalMap(); + void waterSimulation(); + void swapHeightMaps(); + + float mTime; + + Ogre::Vector2 mRippleCenter; + + Ogre::Vector2 mTexelOffset; + + Ogre::Vector2 mCurrentFrameOffset; + Ogre::Vector2 mPreviousFrameOffset; +}; + +} + +#endif diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 27b9fc6793..6ee3890dda 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -12,6 +12,7 @@ #include "sky.hpp" #include "renderingmanager.hpp" #include "compositors.hpp" +#include "ripplesimulation.hpp" #include #include @@ -180,8 +181,11 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mActive(1), mToggled(1), mRendering(rend), mWaterTimer(0.f), - mReflection(NULL) + mReflection(NULL), + mSimulation(NULL) { + mSimulation = new RippleSimulation(mSceneMgr); + mSky = rend->getSkyManager(); mMaterial = MaterialManager::getSingleton().getByName("Water"); @@ -375,7 +379,7 @@ void Water::updateVisible() } } -void Water::update(float dt) +void Water::update(float dt, Ogre::Vector3 player) { /* Ogre::Vector3 pos = mCamera->getDerivedPosition (); @@ -387,6 +391,12 @@ void Water::update(float dt) sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); + + //if (player.y <= mTop) + { + mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); + } + mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); } void Water::applyRTT() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index de78542b72..97eb590b3d 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -29,6 +29,7 @@ namespace MWRender { class SkyManager; class RenderingManager; + class RippleSimulation; class Reflection { @@ -110,6 +111,8 @@ namespace MWRender { float mWaterTimer; + RippleSimulation* mSimulation; + Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); protected: @@ -137,7 +140,7 @@ namespace MWRender { void setActive(bool active); void toggle(); - void update(float dt); + void update(float dt, Ogre::Vector3 player); void assignTextures(); diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 82d6648110..6e87800e5e 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -219,6 +219,8 @@ namespace sh break; } + std::cout << "loading " << it->first << std::endl; + MaterialInstance newInstance(it->first, this); newInstance.create(mPlatform); if (!mShadersEnabled) diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index e8426afb70..65ebc31a2c 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -3,6 +3,7 @@ project(resources) set(WATER_FILES underwater_dome.mesh water_nm.png + circle.png ) set(GBUFFER_FILES @@ -43,6 +44,12 @@ set(MATERIAL_FILES selection.mat selection.shader selection.shaderset + watersim_heightmap.shader + watersim_addimpulse.shader + watersim_heighttonormal.shader + watersim_common.h + watersim.mat + watersim.shaderset ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/core.h b/files/materials/core.h index 0e46369efd..e498a38090 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -28,6 +28,8 @@ #define shNormalInput(type) , in type normal : NORMAL #define shColourInput(type) , in type colour : COLOR + + #define shFract(val) frac(val) #ifdef SH_VERTEX_SHADER @@ -64,6 +66,8 @@ #if SH_GLSL == 1 + #define shFract(val) fract(val) + @version 120 #define float2 vec2 diff --git a/files/materials/quad.mat b/files/materials/quad.mat index afb7f51117..a484d7f28f 100644 --- a/files/materials/quad.mat +++ b/files/materials/quad.mat @@ -4,7 +4,7 @@ material quad pass { - vertex_program quad_vertex + vertex_program transform_vertex fragment_program quad_fragment depth_write $depth_write diff --git a/files/materials/quad.shaderset b/files/materials/quad.shaderset index c614975034..ee230a303d 100644 --- a/files/materials/quad.shaderset +++ b/files/materials/quad.shaderset @@ -1,4 +1,4 @@ -shader_set quad_vertex +shader_set transform_vertex { source quad.shader type vertex diff --git a/files/materials/water.mat b/files/materials/water.mat index a5f9f2ec9e..c427447d24 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -34,7 +34,13 @@ material Water { direct_texture water_nm.png } - + + texture_unit rippleNormalMap + { + direct_texture RippleNormal + tex_address_mode border + tex_border_colour 0.5 0.5 1.0 + } // for simple_water texture_unit animatedTexture diff --git a/files/materials/water.shader b/files/materials/water.shader index 9ebea0f002..1e14dd5962 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -61,7 +61,7 @@ // Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) - +#define RIPPLES 1 #ifdef SH_VERTEX_SHADER @@ -119,8 +119,8 @@ #define WAVE_SCALE 75 // overall wave scale #define BUMP 1.5 // overall water surface bumpiness - #define REFL_BUMP 0.08 // reflection distortion amount - #define REFR_BUMP 0.06 // refraction distortion amount + #define REFL_BUMP 0.16 // reflection distortion amount + #define REFR_BUMP 0.12 // refraction distortion amount #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering @@ -159,6 +159,11 @@ shInput(float3, screenCoordsPassthrough) shInput(float4, position) shInput(float, depthPassthrough) + + #if RIPPLES + shUniform(float3, rippleCenter) @shSharedParameter(rippleCenter, rippleCenter) + shUniform(float, rippleAreaLength) @shSharedParameter(rippleAreaLength, rippleAreaLength) + #endif shUniform(float, far) @shAutoConstant(far, far_clip_distance) @@ -166,6 +171,11 @@ shSampler2D(refractionMap) shSampler2D(depthMap) shSampler2D(normalMap) + + #if RIPPLES + shSampler2D(rippleNormalMap) + shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) + #endif shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #define WIND_SPEED windDir_windSpeed.z @@ -220,8 +230,14 @@ float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xzy; - - normal = normalize(float3(normal.x * BUMP, normal.y, normal.z * BUMP)); + + float4 worldPosition = shMatrixMult(wMat, float4(position.xyz, 1)); + float2 relPos = (worldPosition.xz - rippleCenter.xy) / rippleAreaLength + 0.5; + float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2 - 1); + normal_ripple = normal_ripple.xzy; + + normal = normalize(normal + normal_ripple); + // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + @@ -303,7 +319,7 @@ } shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); - + //shOutputColour(0).xyz = float3(relPos.x, relPos.y, 0); shOutputColour(0).w = 1; } diff --git a/files/materials/watersim.mat b/files/materials/watersim.mat new file mode 100644 index 0000000000..b58b1a8512 --- /dev/null +++ b/files/materials/watersim.mat @@ -0,0 +1,59 @@ +material HeightmapSimulation +{ + allow_fixed_function false + pass + { + depth_check off + depth_write off + vertex_program transform_vertex + fragment_program watersim_fragment + + texture_unit heightPrevSampler + { + tex_address_mode border + tex_border_colour 0 0 0 + texture_alias Heightmap0 + } + texture_unit heightCurrentSampler + { + tex_address_mode border + tex_border_colour 0 0 0 + texture_alias Heightmap1 + } + } +} + +material HeightToNormalMap +{ + allow_fixed_function false + pass + { + depth_check off + depth_write off + vertex_program transform_vertex + fragment_program height_to_normal_fragment + + texture_unit heightCurrentSampler + { + texture_alias Heightmap2 + } + } +} + +material AddImpulse +{ + allow_fixed_function false + pass + { + depth_check off + depth_write off + scene_blend alpha_blend + vertex_program transform_vertex + fragment_program add_impulse_fragment + + texture_unit alphaMap + { + texture circle.png + } + } +} diff --git a/files/materials/watersim.shaderset b/files/materials/watersim.shaderset new file mode 100644 index 0000000000..ea512e25f0 --- /dev/null +++ b/files/materials/watersim.shaderset @@ -0,0 +1,31 @@ +shader_set transform_vertex +{ + source quad.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set watersim_fragment +{ + source watersim_heightmap.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} + +shader_set height_to_normal_fragment +{ + source watersim_heighttonormal.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} + +shader_set add_impulse_fragment +{ + source watersim_addimpulse.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} diff --git a/files/materials/watersim_addimpulse.shader b/files/materials/watersim_addimpulse.shader new file mode 100644 index 0000000000..3ca4192cd7 --- /dev/null +++ b/files/materials/watersim_addimpulse.shader @@ -0,0 +1,12 @@ +#include "core.h" +#include "watersim_common.h" + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shSampler2D(alphaMap) + + SH_START_PROGRAM + { + shOutputColour(0) = EncodeHeightmap(1.0); + shOutputColour(0).a = shSample (alphaMap, UV.xy).a; + } diff --git a/files/materials/watersim_common.h b/files/materials/watersim_common.h new file mode 100644 index 0000000000..aa7a636a06 --- /dev/null +++ b/files/materials/watersim_common.h @@ -0,0 +1,25 @@ +float DecodeHeightmap(float4 heightmap) +{ + float4 table = float4(1.0, -1.0, 0.0, 0.0); + return dot(heightmap, table); +} + +float DecodeHeightmap(shTexture2D HeightmapSampler, float2 texcoord) +{ + float4 heightmap = shSample(HeightmapSampler, texcoord); + return DecodeHeightmap(heightmap); +} + +float4 EncodeHeightmap(float fHeight) +{ + float h = fHeight; + float positive = fHeight > 0.0 ? fHeight : 0.0; + float negative = fHeight < 0.0 ? -fHeight : 0.0; + + float4 color = float4(0,0,0,0); + + color.r = positive; + color.g = negative; + + return color; +} diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader new file mode 100644 index 0000000000..e19270d39e --- /dev/null +++ b/files/materials/watersim_heightmap.shader @@ -0,0 +1,42 @@ +#include "core.h" + +#define DAMPING 0.92 + +#include "watersim_common.h" + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shSampler2D(heightPrevSampler) + shSampler2D(heightCurrentSampler) + shUniform(float3, previousFrameOffset) @shSharedParameter(previousFrameOffset, previousFrameOffset) + shUniform(float3, currentFrameOffset) @shSharedParameter(currentFrameOffset, currentFrameOffset) + shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) + + SH_START_PROGRAM + { + const float3 offset[4] = float3[4]( + float3(-1.0, 0.0, 0.25), + float3( 1.0, 0.0, 0.25), + float3( 0.0,-1.0, 0.25), + float3( 0.0, 1.0, 0.25) + ); + + float fHeightPrev = DecodeHeightmap(heightPrevSampler, UV.xy + previousFrameOffset.xy + currentFrameOffset.xy); + + float fNeighCurrent = 0; + for ( int i=0; i<4; i++ ) + { + float2 vTexcoord = UV + currentFrameOffset.xy + offset[i].xy * rippleTextureSize.xy; + fNeighCurrent += (DecodeHeightmap(heightCurrentSampler, vTexcoord) * offset[i].z); + } + + float fHeight = fNeighCurrent * 2.0 - fHeightPrev; + + fHeight *= DAMPING; + + shOutputColour(0) = EncodeHeightmap(fHeight); + } + + + + diff --git a/files/materials/watersim_heighttonormal.shader b/files/materials/watersim_heighttonormal.shader new file mode 100644 index 0000000000..5402b6bb5e --- /dev/null +++ b/files/materials/watersim_heighttonormal.shader @@ -0,0 +1,27 @@ +#include "core.h" +#include "watersim_common.h" + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shSampler2D(heightCurrentSampler) + shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) + + SH_START_PROGRAM + { + float2 offset[4] = float2[4] ( + vec2(-1.0, 0.0), + vec2( 1.0, 0.0), + vec2( 0.0,-1.0), + vec2( 0.0, 1.0) + ); + + float fHeightL = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[0]*rippleTextureSize.xy); + float fHeightR = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[1]*rippleTextureSize.xy); + float fHeightT = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[2]*rippleTextureSize.xy); + float fHeightB = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[3]*rippleTextureSize.xy); + + float3 n = float3(fHeightB - fHeightT, fHeightR - fHeightL, 1.0); + float3 normal = (n + 1.0) * 0.5; + + shOutputColour(0) = float4(normal.rgb, 1.0); + } diff --git a/files/water/circle.png b/files/water/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1cf268c0be2cdae27fe04ee7f7c0aa6de12c11 GIT binary patch literal 753 zcmVPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RY0s#yODLP_H6#xJL8FWQhbVF}# zZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b0$xc(K~#9!?VG<&8$l4pf3r}yK~51x zqM)L&3(GXPrAgYOr>3Lk4JgeU@D%ooAf>PicNCFA3Q(Fz0Zj_eDdq^q=iI@0XFq8g z%YXL!d^@wd^R1{VbwWh8fL)*q99VRLJ>Vno0NepLzy!Fqm;m2Y^|96gs%qr{w1Es5 z0s5aYvhQlwGS&)73oxjN^fEC9fHXz`BmM=rt&w;!ZtXYaT?GL8!0Zi)7h?wW-&_Eo z1q|Pjcrk`RYaK39whD+y2lxtX(=0pyJyo5S`A{fHKC|-FH1gP(CN{?E%OG&pphy0- zIIA=V0OuP-K9BQC1lX{DzVwsu8u@I4$>))+B>>QgfP5aEQe{v?TENeSX8UzZkrykKL0jHxq|slR18ie6i&%hJaRXJH0-u3>;>Esk{G0FcBq$;Re794Y znDGPnq(*%42{?2>9^-iUED6?plGC&pJy{2cNZSr3J>i3@-se-`2!A+Q%mJqk1vt&? z{+2BjJz_gp)50rugLP@Vq8qGLfHVc>U0Sc$6X17bhaaU*iUQ6N9PR-YaTl07 zGrZy^Fz@ww#UwEI<9Nk&62SWuNZVoa;f)=VAFJwPz7V={D8Lnv4n+fis@^-B24my= zq%SbQPhVj0%pc&sHD)iIIC%U|bkP;!y*-``5-%8}h7pn{vCMkPkFQUZP`xp5a z1uzk&z;OiRkC!^glT|jErITI0j0l@xp3c&hnGz`78L}VP0WKRv{?h9Flr;#YYjf%1 jWV$-*_wuxOzdrv5<*cfu_Ri)S00000NkvXXu0mjfBzZwt literal 0 HcmV?d00001 From 4e46f403a9710ed3cda61b6615e3c0c7bdf992d8 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 28 Jan 2013 22:07:39 -0800 Subject: [PATCH 0192/1483] added some more warning to ignore in MSVC --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2313d2d958..9c4ce5cd8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -496,7 +496,7 @@ if (WIN32) # Warnings that aren't enabled normally and don't need to be enabled # They're unneeded and sometimes completely retarded warnings that /Wall enables # Not going to bother commenting them as they tend to warn on every standard library files - 4061 4263 4264 4266 4350 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 + 4061 4263 4264 4266 4350 4371 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 # Warnings that are thrown on standard libraries and not OpenMW 4347 # Non-template function with same name and parameter count as template function @@ -506,6 +506,11 @@ if (WIN32) 4738 # Storing 32-bit float result in memory, possible loss of performance 4986 # Undocumented warning that occurs in the crtdbg.h file 4996 # Function was declared deprecated + + # cause by ogre extensivly + 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' + 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' + 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type From 7f87c1873b4fbd4b27590d1313f8a15bd1ba55cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 02:53:22 -0800 Subject: [PATCH 0193/1483] Use an array to store the entity parts --- apps/openmw/mwrender/npcanimation.cpp | 62 +++++++++++++-------------- apps/openmw/mwrender/npcanimation.hpp | 31 +------------- 2 files changed, 33 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 03fda89820..18f44c87ca 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -16,39 +16,39 @@ namespace MWRender { const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { - { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, - { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, - { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, - { ESM::PRT_Cuirass, &NpcAnimation::mChest, "Chest" }, - { ESM::PRT_Groin, &NpcAnimation::mGroin, "Groin" }, - { ESM::PRT_Skirt, &NpcAnimation::mSkirt, "Groin" }, - { ESM::PRT_RHand, &NpcAnimation::mHandR, "Right Hand" }, - { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, - { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, - { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, - { ESM::PRT_Shield, &NpcAnimation::mShield, "Shield" }, - { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, - { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, - { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, - { ESM::PRT_LUpperarm, &NpcAnimation::mUpperArmL, "Left Upper Arm" }, - { ESM::PRT_RFoot, &NpcAnimation::mFootR, "Right Foot" }, - { ESM::PRT_LFoot, &NpcAnimation::mFootL, "Left Foot" }, - { ESM::PRT_RAnkle, &NpcAnimation::mAnkleR, "Right Ankle" }, - { ESM::PRT_LAnkle, &NpcAnimation::mAnkleL, "Left Ankle" }, - { ESM::PRT_RKnee, &NpcAnimation::mKneeR, "Right Knee" }, - { ESM::PRT_LKnee, &NpcAnimation::mKneeL, "Left Knee" }, - { ESM::PRT_RLeg, &NpcAnimation::mUpperLegR, "Right Upper Leg" }, - { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, - { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, - { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, - { ESM::PRT_Weapon, &NpcAnimation::mWeapon, "Weapon" }, - { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } + { ESM::PRT_Head, "Head" }, + { ESM::PRT_Hair, "Head" }, + { ESM::PRT_Neck, "Neck" }, + { ESM::PRT_Cuirass, "Chest" }, + { ESM::PRT_Groin, "Groin" }, + { ESM::PRT_Skirt, "Groin" }, + { ESM::PRT_RHand, "Right Hand" }, + { ESM::PRT_LHand, "Left Hand" }, + { ESM::PRT_RWrist, "Right Wrist" }, + { ESM::PRT_LWrist, "Left Wrist" }, + { ESM::PRT_Shield, "Shield" }, + { ESM::PRT_RForearm, "Right Forearm" }, + { ESM::PRT_LForearm, "Left Forearm" }, + { ESM::PRT_RUpperarm, "Right Upper Arm" }, + { ESM::PRT_LUpperarm, "Left Upper Arm" }, + { ESM::PRT_RFoot, "Right Foot" }, + { ESM::PRT_LFoot, "Left Foot" }, + { ESM::PRT_RAnkle, "Right Ankle" }, + { ESM::PRT_LAnkle, "Left Ankle" }, + { ESM::PRT_RKnee, "Right Knee" }, + { ESM::PRT_LKnee, "Left Knee" }, + { ESM::PRT_RLeg, "Right Upper Leg" }, + { ESM::PRT_LLeg, "Left Upper Leg" }, + { ESM::PRT_RPauldron, "Right Clavicle" }, + { ESM::PRT_LPauldron, "Left Clavicle" }, + { ESM::PRT_Weapon, "Weapon" }, + { ESM::PRT_Tail, "Tail" } }; NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - removeEntities(this->*sPartList[i].ents); + removeEntities(mEntityParts[i]); } @@ -336,7 +336,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { - Ogre::Entity *ent = (this->*sPartList[i].ents).mSkelBase; + Ogre::Entity *ent = mEntityParts[i].mSkelBase; if(!ent) continue; updateSkeletonInstance(skelsrc, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); @@ -367,7 +367,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeEntities(this->*sPartList[i].ents); + removeEntities(mEntityParts[i]); break; } } @@ -405,7 +405,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); + mEntityParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index a4e87e7224..513741d039 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -19,7 +19,6 @@ class NpcAnimation : public Animation public: struct PartInfo { ESM::PartReferenceType type; - NifOgre::EntityList NpcAnimation::*ents; const char name[32]; }; @@ -30,34 +29,8 @@ private: MWWorld::InventoryStore& mInv; int mStateID; - //Bounded Parts - NifOgre::EntityList mClavicleL; - NifOgre::EntityList mClavicleR; - NifOgre::EntityList mUpperArmL; - NifOgre::EntityList mUpperArmR; - NifOgre::EntityList mUpperLegL; - NifOgre::EntityList mUpperLegR; - NifOgre::EntityList mForearmL; - NifOgre::EntityList mForearmR; - NifOgre::EntityList mWristL; - NifOgre::EntityList mWristR; - NifOgre::EntityList mKneeR; - NifOgre::EntityList mKneeL; - NifOgre::EntityList mNeck; - NifOgre::EntityList mAnkleL; - NifOgre::EntityList mAnkleR; - NifOgre::EntityList mGroin; - NifOgre::EntityList mSkirt; - NifOgre::EntityList mFootL; - NifOgre::EntityList mFootR; - NifOgre::EntityList mHair; - NifOgre::EntityList mHandL; - NifOgre::EntityList mHandR; - NifOgre::EntityList mShield; - NifOgre::EntityList mWeapon; - NifOgre::EntityList mHead; - NifOgre::EntityList mChest; - NifOgre::EntityList mTail; + // Bounded Parts + NifOgre::EntityList mEntityParts[sPartListSize]; const ESM::NPC *mNpc; std::string mHeadModel; From 85697e4628d3cd983f7b706dc890da97e0634027 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Feb 2013 13:24:28 +0100 Subject: [PATCH 0194/1483] reverted to C++03 --- CMakeLists.txt | 4 ++-- apps/openmw/mwworld/actionequip.cpp | 12 ++++++------ components/bsa/bsa_archive.cpp | 2 +- components/files/constrainedfiledatastream.cpp | 9 +++------ 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c4ce5cd8e..c944730ab0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,7 +306,7 @@ endif() # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++0x -pedantic) + add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++03 -pedantic -Wno-long-long) # Silence warnings in OGRE headers. Remove once OGRE got fixed! add_definitions (-Wno-ignored-qualifiers) @@ -506,7 +506,7 @@ if (WIN32) 4738 # Storing 32-bit float result in memory, possible loss of performance 4986 # Undocumented warning that occurs in the crtdbg.h file 4996 # Function was declared deprecated - + # cause by ogre extensivly 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 60260a812b..f3191e8bb2 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -32,7 +32,7 @@ namespace MWWorld } assert(it != invStore.end()); - + std::string npcRace = actor.get()->mBase->mRace; // equip the item in the first free slot @@ -43,7 +43,7 @@ namespace MWWorld // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) if(npcRace == "argonian" || npcRace == "khajiit") { - if(*slot == MWWorld::InventoryStore::Slot_Helmet){ + if(*slot == MWWorld::InventoryStore::Slot_Helmet){ std::vector parts; if(it.getType() == MWWorld::ContainerStore::Type_Clothing) @@ -54,22 +54,22 @@ namespace MWWorld bool allow = true; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { - if((*itr).mPart == ESM::PartReferenceType::PRT_Head) + if((*itr).mPart == ESM::PRT_Head) { if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector()); - + allow = false; break; } } - + if(!allow) break; } if (*slot == MWWorld::InventoryStore::Slot_Boots) - { + { // Only notify the player, not npcs if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) { diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 5274564a63..8117dbdfd7 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -91,7 +91,7 @@ public: std::string searchable = normalize_path (proper.begin () + prefix, proper.end ()); - mIndex.insert (std::make_pair (std::move (searchable), std::move (proper))); + mIndex.insert (std::make_pair (searchable, proper)); } } diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp index dd2985e561..321bcf7c8c 100644 --- a/components/files/constrainedfiledatastream.cpp +++ b/components/files/constrainedfiledatastream.cpp @@ -3,11 +3,8 @@ #include #include -#ifndef __clang__ -#include -#else -#include -#endif + +#include namespace { @@ -29,7 +26,7 @@ public: mBufferOrigin = 0; mBufferExtent = 0; } - + size_t read(void* buf, size_t count) { From 827261e8b4c4fb2761429fa79c1c88721ae1602e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Feb 2013 13:42:11 +0100 Subject: [PATCH 0195/1483] increased version number --- CMakeLists.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c944730ab0..165db6b792 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 20) +set (OPENMW_VERSION_MINOR 21) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") diff --git a/readme.txt b/readme.txt index 21ae855309..d94ccd7f08 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.20.0 +Version: 0.21.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From e6e7c69013070bd1c76f13a5d98739a9fc850fdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 05:26:52 -0800 Subject: [PATCH 0196/1483] Fix handling of filtered entities --- components/nifogre/ogre_nif_loader.cpp | 33 +++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9c9fd3b22f..2da8033e66 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -1212,16 +1213,8 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); - if(ent->hasSkeleton()) - { - if(meshes[i].mMeshName.find(filter) == std::string::npos) - { - sceneMgr->destroyEntity(ent); - continue; - } - if(!entitylist.mSkelBase) - entitylist.mSkelBase = ent; - } + if(!entitylist.mSkelBase && ent->hasSkeleton()) + entitylist.mSkelBase = ent; entitylist.mEntities.push_back(ent); } @@ -1231,19 +1224,25 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(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()) + if(entity->hasSkeleton()) { - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - parentNode->attachObject(entity); + if(entity != entitylist.mSkelBase) + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); + if(entity->getMesh()->getName().find(filter) != std::string::npos) + parentNode->attachObject(entity); } - else if(entity != entitylist.mSkelBase) + else { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(bonename, entity); - tag->setScale(scale); + if(entity->getMesh()->getName().find(filter) != std::string::npos) + { + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + tag->setPosition(meshes[i].mPos); + tag->setOrientation(meshes[i].mRot); + tag->setScale(Ogre::Vector3(meshes[i].mScale)); + } } } } From fc7590694d11a1e6281fa203102ef1e0074d645a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 05:43:37 -0800 Subject: [PATCH 0197/1483] Revert "Revert "Use a child scene node for the accumulation root"" This reverts commit 376dfed15ba01cee8d24d122dfafc797a86fd303. I was wrong. It's needed at least for NPCs since they're attaching multiple animated skeletons to an object, and they all need to be offset correctly. Would be nice to use a Node, Bone, or TagPoint instead of a hefty SceneNode, though. --- apps/openmw/mwrender/animation.cpp | 5 ++--- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b63de2f166..b811040676 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node; + mInsert = node->createChildSceneNode(); assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,8 +76,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); + mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 60e524d280..165a6525c3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Bone *mAccumRoot; + Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From c23a96d6065ae0ca8a452624be8711bff0985f8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 06:08:03 -0800 Subject: [PATCH 0198/1483] Run an aniamtion update after "playing" the inventory idle This is so all the NPC parts get updated correctly. --- apps/openmw/mwrender/characterpreview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 5a1a93311b..8f0440b116 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -145,6 +145,7 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->play("inventoryhandtohand", "start", false); + mAnimation->runAnimation(0.0f); } // -------------------------------------------------------------------------------------------------- From 67a1ec51665822ea03fa89906488a7872566f5c8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Feb 2013 16:14:58 +0100 Subject: [PATCH 0199/1483] added provisional startup dialogue --- apps/opencs/CMakeLists.txt | 4 +-- apps/opencs/editor.cpp | 46 ++++++++++++++++++++++++++-- apps/opencs/editor.hpp | 7 ++++- apps/opencs/view/doc/startup.cpp | 20 ++++++++++++ apps/opencs/view/doc/startup.hpp | 24 +++++++++++++++ apps/opencs/view/doc/view.cpp | 4 +++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/doc/viewmanager.cpp | 1 + apps/opencs/view/doc/viewmanager.hpp | 2 ++ 9 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 apps/opencs/view/doc/startup.cpp create mode 100644 apps/opencs/view/doc/startup.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index abbc953ca4..d3634a66e4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -12,7 +12,7 @@ set (OPENCS_SRC model/tools/mandatoryid.cpp model/tools/reportmodel.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp - view/doc/subview.cpp + view/doc/subview.cpp view/doc/startup.cpp view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp view/world/dialoguesubview.cpp @@ -33,7 +33,7 @@ set (OPENCS_HDR model/tools/mandatoryid.hpp model/tools/reportmodel.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp - view/doc/subview.hpp view/doc/subviewfactoryimp.hpp + view/doc/subview.hpp view/doc/subviewfactoryimp.hpp view/doc/startup.hpp view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp view/world/dialoguesubview.hpp diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 1632ed220d..2340c71ee2 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -11,10 +11,19 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) { connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); + connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); + + connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); + connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); } void CS::Editor::createDocument() { + mStartup.hide(); + + /// \todo open the ESX picker instead + /// \todo remove the following code for creating initial records into the document manager + std::ostringstream stream; stream << "NewDocument" << (++mNewDocumentIndex); @@ -23,7 +32,39 @@ void CS::Editor::createDocument() static const char *sGlobals[] = { - "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + }; + + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global record; + record.mId = sGlobals[i]; + record.mValue = i==0 ? 1 : 0; + record.mType = ESM::VT_Float; + document->getData().getGlobals().add (record); + } + + document->getData().merge(); /// \todo remove once proper ESX loading is implemented + + mViewManager.addView (document); +} + +void CS::Editor::loadDocument() +{ + mStartup.hide(); + + /// \todo open the ESX picker instead + /// \todo replace the manual record creation and load the ESX files instead + + std::ostringstream stream; + + stream << "Document" << (++mNewDocumentIndex); + + CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); + + static const char *sGlobals[] = + { + "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 }; for (int i=0; sGlobals[i]; ++i) @@ -42,8 +83,7 @@ void CS::Editor::createDocument() int CS::Editor::run() { - /// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects - createDocument(); + mStartup.show(); return QApplication::exec(); } \ No newline at end of file diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 60f7beaf1d..0cd780f7fc 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -4,7 +4,9 @@ #include #include "model/doc/documentmanager.hpp" + #include "view/doc/viewmanager.hpp" +#include "view/doc/startup.hpp" namespace CS { @@ -16,6 +18,7 @@ namespace CS CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; + CSVDoc::StartupDialogue mStartup; // not implemented Editor (const Editor&); @@ -28,9 +31,11 @@ namespace CS int run(); ///< \return error status - public slots: + private slots: void createDocument(); + + void loadDocument(); }; } diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp new file mode 100644 index 0000000000..7861a1c2ef --- /dev/null +++ b/apps/opencs/view/doc/startup.cpp @@ -0,0 +1,20 @@ + +#include "startup.hpp" + +#include +#include + +CSVDoc::StartupDialogue::StartupDialogue() +{ + QHBoxLayout *layout = new QHBoxLayout (this); + + QPushButton *createDocument = new QPushButton ("new", this); + connect (createDocument, SIGNAL (clicked()), this, SIGNAL (createDocument())); + layout->addWidget (createDocument); + + QPushButton *loadDocument = new QPushButton ("load", this); + connect (loadDocument, SIGNAL (clicked()), this, SIGNAL (loadDocument())); + layout->addWidget (loadDocument); + + setLayout (layout); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/startup.hpp b/apps/opencs/view/doc/startup.hpp new file mode 100644 index 0000000000..f24d2a64ba --- /dev/null +++ b/apps/opencs/view/doc/startup.hpp @@ -0,0 +1,24 @@ +#ifndef CSV_DOC_STARTUP_H +#define CSV_DOC_STARTUP_H + +#include + +namespace CSVDoc +{ + class StartupDialogue : public QWidget + { + Q_OBJECT + + public: + + StartupDialogue(); + + signals: + + void createDocument(); + + void loadDocument(); + }; +} + +#endif diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 13edb6e749..d6639e59ca 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -32,6 +32,10 @@ void CSVDoc::View::setupFileMenu() connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); file->addAction (new_); + QAction *open = new QAction (tr ("Open"), this); + connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest())); + file->addAction (open); + mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index b1dedafe92..05d7210dce 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -84,6 +84,8 @@ namespace CSVDoc void newDocumentRequest(); + void loadDocumentRequest(); + public slots: void addSubView (const CSMWorld::UniversalId& id); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 22847c78b7..b01b9ce342 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -57,6 +57,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) view->show(); connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest())); + connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); updateIndices(); diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 5e4b1be075..91a80d4962 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -46,6 +46,8 @@ namespace CSVDoc void newDocumentRequest(); + void loadDocumentRequest(); + private slots: void documentStateChanged (int state, CSMDoc::Document *document); From 155cca0c9a23eec9db94f2e9214110029a0a4838 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sat, 2 Feb 2013 16:25:41 +0100 Subject: [PATCH 0200/1483] Upload missing files. Fix folder name. Keep Qt optional. Move open dialogue from doc to tools. Rename 'load' to 'open'. Deleted wrong comment. --- apps/launcher/graphicspage.cpp | 2 +- apps/launcher/maindialog.cpp | 2 +- apps/opencs/CMakeLists.txt | 8 +++--- apps/opencs/view/doc/opendialog.cpp | 27 +++++++++++++++++++ apps/opencs/view/doc/opendialog.hpp | 17 ++++++++++++ apps/opencs/view/doc/view.cpp | 16 +++++------ apps/opencs/view/doc/view.hpp | 6 ++--- components/CMakeLists.txt | 16 ++++++----- .../datafileslist.cpp | 0 .../datafileslist.hpp | 0 .../model/datafilesmodel.cpp | 0 .../model/datafilesmodel.hpp | 0 .../model/esm/esmfile.cpp | 0 .../model/esm/esmfile.hpp | 0 .../model/modelitem.cpp | 0 .../model/modelitem.hpp | 0 .../utils/filedialog.cpp | 0 .../utils/filedialog.hpp | 0 .../utils/lineedit.cpp | 0 .../utils/lineedit.hpp | 0 .../utils/naturalsort.cpp | 0 .../utils/naturalsort.hpp | 0 .../utils/profilescombobox.cpp | 0 .../utils/profilescombobox.hpp | 0 .../utils/textinputdialog.cpp | 0 .../utils/textinputdialog.hpp | 0 26 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 apps/opencs/view/doc/opendialog.cpp create mode 100644 apps/opencs/view/doc/opendialog.hpp rename components/{file_order_list => fileorderlist}/datafileslist.cpp (100%) rename components/{file_order_list => fileorderlist}/datafileslist.hpp (100%) rename components/{file_order_list => fileorderlist}/model/datafilesmodel.cpp (100%) rename components/{file_order_list => fileorderlist}/model/datafilesmodel.hpp (100%) rename components/{file_order_list => fileorderlist}/model/esm/esmfile.cpp (100%) rename components/{file_order_list => fileorderlist}/model/esm/esmfile.hpp (100%) rename components/{file_order_list => fileorderlist}/model/modelitem.cpp (100%) rename components/{file_order_list => fileorderlist}/model/modelitem.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/filedialog.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/filedialog.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/lineedit.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/lineedit.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/naturalsort.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/naturalsort.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/profilescombobox.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/profilescombobox.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/textinputdialog.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/textinputdialog.hpp (100%) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index e69a8c2077..dee84498c2 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "graphicspage.hpp" diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 43b8f317ab..7914650fe9 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include "maindialog.hpp" #include "playpage.hpp" diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 68b22c10ef..76d669e151 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -12,12 +12,12 @@ set (OPENCS_SRC model/tools/mandatoryid.cpp model/tools/reportmodel.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp - view/doc/subview.cpp + view/doc/subview.cpp view/doc/opendialog.cpp view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp view/world/dialoguesubview.cpp - view/tools/reportsubview.cpp view/tools/subviews.cpp view/tools/opendialog.cpp + view/tools/reportsubview.cpp view/tools/subviews.cpp ) set (OPENCS_HDR @@ -33,12 +33,12 @@ set (OPENCS_HDR model/tools/mandatoryid.hpp model/tools/reportmodel.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp - view/doc/subview.hpp view/doc/subviewfactoryimp.hpp + view/doc/subview.hpp view/doc/subviewfactoryimp.hpp view/doc/opendialog.hpp view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp view/world/dialoguesubview.hpp - view/tools/reportsubview.hpp view/tools/subviews.hpp view/tools/opendialog.hpp + view/tools/reportsubview.hpp view/tools/subviews.hpp ) set (OPENCS_US diff --git a/apps/opencs/view/doc/opendialog.cpp b/apps/opencs/view/doc/opendialog.cpp new file mode 100644 index 0000000000..f51cbadb97 --- /dev/null +++ b/apps/opencs/view/doc/opendialog.cpp @@ -0,0 +1,27 @@ +#include +#include + +#include + +#include "opendialog.hpp" + +OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + mFileSelector = new DataFilesList(mCfgMgr, this); + layout->addWidget(mFileSelector); + mFileSelector->setupDataFiles(); + + buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + layout->addWidget(buttonBox); + + setLayout(layout); + setWindowTitle(tr("Open")); +} + +void OpenDialog::getFileList(std::vector& paths) +{ + mFileSelector->getSelectedFiles(paths); +} diff --git a/apps/opencs/view/doc/opendialog.hpp b/apps/opencs/view/doc/opendialog.hpp new file mode 100644 index 0000000000..6355aea44f --- /dev/null +++ b/apps/opencs/view/doc/opendialog.hpp @@ -0,0 +1,17 @@ +#include +#include + +class DataFilesList; +class QDialogButtonBox; + +class OpenDialog : public QDialog { + Q_OBJECT +public: + OpenDialog(QWidget * parent = 0); + + void getFileList(std::vector& paths); +private: + DataFilesList * mFileSelector; + QDialogButtonBox * buttonBox; + Files::ConfigurationManager mCfgMgr; +}; \ No newline at end of file diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ebcb9aaa7f..112807cca0 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -14,8 +14,7 @@ #include "../tools/subviews.hpp" -#include "../tools/opendialog.hpp" - +#include "opendialog.hpp" #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -34,9 +33,9 @@ void CSVDoc::View::setupFileMenu() connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); file->addAction (new_); - mLoad = new QAction(tr ("&Load"), this); - connect (mLoad, SIGNAL (triggered()), this, SLOT (load())); - file->addAction (mLoad); + mOpen = new QAction(tr ("&Open"), this); + connect (mOpen, SIGNAL (triggered()), this, SLOT (open())); + file->addAction (mOpen); mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); @@ -211,11 +210,11 @@ void CSVDoc::View::save() mDocument->save(); } -void CSVDoc::View::load() +void CSVDoc::View::open() { if (!mOpenDialog) { mOpenDialog = new OpenDialog(this); - connect(mOpenDialog, SIGNAL(accepted()), this, SLOT(loadNewFiles())); + connect(mOpenDialog, SIGNAL(accepted()), this, SLOT(openNewFiles())); } mOpenDialog->show(); @@ -223,9 +222,8 @@ void CSVDoc::View::load() mOpenDialog->activateWindow(); } -void CSVDoc::View::loadNewFiles() +void CSVDoc::View::openNewFiles() { - //FIXME close old files std::vector paths; mOpenDialog->getFileList(paths); //FIXME load new files diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 1822522033..839edf0a55 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -37,7 +37,7 @@ namespace CSVDoc QAction *mUndo; QAction *mRedo; QAction *mSave; - QAction *mLoad; + QAction *mOpen; QAction *mVerify; std::vector mEditingActions; Operations *mOperations; @@ -95,8 +95,8 @@ namespace CSVDoc void newView(); - void load(); - void loadNewFiles(); + void open(); + void openNewFiles(); void save(); void verify(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3798f66b7a..63a2276217 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -66,15 +66,17 @@ add_component_dir (translation translation ) -add_component_qt_dir (file_order_list - datafileslist model/modelitem model/datafilesmodel model/esm/esmfile - utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort - ) +find_package(Qt4 COMPONENTS QtCore QtGui) -find_package(Qt4 COMPONENTS QtCore QtGUI REQUIRED) -include(${QT_USE_FILE}) +if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) + add_component_qt_dir (fileorderlist + datafileslist model/modelitem model/datafilesmodel model/esm/esmfile + utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort + ) -QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + include(${QT_USE_FILE}) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) +endif(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) include_directories(${BULLET_INCLUDE_DIRS}) diff --git a/components/file_order_list/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp similarity index 100% rename from components/file_order_list/datafileslist.cpp rename to components/fileorderlist/datafileslist.cpp diff --git a/components/file_order_list/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp similarity index 100% rename from components/file_order_list/datafileslist.hpp rename to components/fileorderlist/datafileslist.hpp diff --git a/components/file_order_list/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp similarity index 100% rename from components/file_order_list/model/datafilesmodel.cpp rename to components/fileorderlist/model/datafilesmodel.cpp diff --git a/components/file_order_list/model/datafilesmodel.hpp b/components/fileorderlist/model/datafilesmodel.hpp similarity index 100% rename from components/file_order_list/model/datafilesmodel.hpp rename to components/fileorderlist/model/datafilesmodel.hpp diff --git a/components/file_order_list/model/esm/esmfile.cpp b/components/fileorderlist/model/esm/esmfile.cpp similarity index 100% rename from components/file_order_list/model/esm/esmfile.cpp rename to components/fileorderlist/model/esm/esmfile.cpp diff --git a/components/file_order_list/model/esm/esmfile.hpp b/components/fileorderlist/model/esm/esmfile.hpp similarity index 100% rename from components/file_order_list/model/esm/esmfile.hpp rename to components/fileorderlist/model/esm/esmfile.hpp diff --git a/components/file_order_list/model/modelitem.cpp b/components/fileorderlist/model/modelitem.cpp similarity index 100% rename from components/file_order_list/model/modelitem.cpp rename to components/fileorderlist/model/modelitem.cpp diff --git a/components/file_order_list/model/modelitem.hpp b/components/fileorderlist/model/modelitem.hpp similarity index 100% rename from components/file_order_list/model/modelitem.hpp rename to components/fileorderlist/model/modelitem.hpp diff --git a/components/file_order_list/utils/filedialog.cpp b/components/fileorderlist/utils/filedialog.cpp similarity index 100% rename from components/file_order_list/utils/filedialog.cpp rename to components/fileorderlist/utils/filedialog.cpp diff --git a/components/file_order_list/utils/filedialog.hpp b/components/fileorderlist/utils/filedialog.hpp similarity index 100% rename from components/file_order_list/utils/filedialog.hpp rename to components/fileorderlist/utils/filedialog.hpp diff --git a/components/file_order_list/utils/lineedit.cpp b/components/fileorderlist/utils/lineedit.cpp similarity index 100% rename from components/file_order_list/utils/lineedit.cpp rename to components/fileorderlist/utils/lineedit.cpp diff --git a/components/file_order_list/utils/lineedit.hpp b/components/fileorderlist/utils/lineedit.hpp similarity index 100% rename from components/file_order_list/utils/lineedit.hpp rename to components/fileorderlist/utils/lineedit.hpp diff --git a/components/file_order_list/utils/naturalsort.cpp b/components/fileorderlist/utils/naturalsort.cpp similarity index 100% rename from components/file_order_list/utils/naturalsort.cpp rename to components/fileorderlist/utils/naturalsort.cpp diff --git a/components/file_order_list/utils/naturalsort.hpp b/components/fileorderlist/utils/naturalsort.hpp similarity index 100% rename from components/file_order_list/utils/naturalsort.hpp rename to components/fileorderlist/utils/naturalsort.hpp diff --git a/components/file_order_list/utils/profilescombobox.cpp b/components/fileorderlist/utils/profilescombobox.cpp similarity index 100% rename from components/file_order_list/utils/profilescombobox.cpp rename to components/fileorderlist/utils/profilescombobox.cpp diff --git a/components/file_order_list/utils/profilescombobox.hpp b/components/fileorderlist/utils/profilescombobox.hpp similarity index 100% rename from components/file_order_list/utils/profilescombobox.hpp rename to components/fileorderlist/utils/profilescombobox.hpp diff --git a/components/file_order_list/utils/textinputdialog.cpp b/components/fileorderlist/utils/textinputdialog.cpp similarity index 100% rename from components/file_order_list/utils/textinputdialog.cpp rename to components/fileorderlist/utils/textinputdialog.cpp diff --git a/components/file_order_list/utils/textinputdialog.hpp b/components/fileorderlist/utils/textinputdialog.hpp similarity index 100% rename from components/file_order_list/utils/textinputdialog.hpp rename to components/fileorderlist/utils/textinputdialog.hpp From f785659297abf4b23876a875f0da5bdcb0c39ee8 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sat, 2 Feb 2013 17:36:12 +0000 Subject: [PATCH 0201/1483] Implemented OnPCAdd special variable Had to edit OpAddItem in miscextensions.cpp, as local variables were not being initialised for items added through it. Does not get reset on drop, as per original morrowind. --- apps/openmw/mwscript/containerextensions.cpp | 8 ++++++ apps/openmw/mwworld/containerstore.cpp | 28 ++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 1fa69d1fd6..4cce19b862 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -50,6 +50,14 @@ namespace MWScript MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item); ref.getPtr().getRefData().setCount (count); + + // Configure item's script variables + std::string script = MWWorld::Class::get(ref.getPtr()).getScript(ref.getPtr()); + if (script != "") + { + const ESM::Script *esmscript = MWBase::Environment::get().getWorld()->getStore().get().find (script); + ref.getPtr().getRefData().setLocals(*esmscript); + } MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bca4073b52..31eabb3424 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -8,9 +8,11 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/scriptmanager.hpp" #include "manualref.hpp" #include "refdata.hpp" @@ -83,9 +85,31 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) CellStore *cell; Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); - // Items in players inventory have cell set to 0, so their scripts will never be removed + if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) - cell = 0; + { + cell = 0; // Items in players inventory have cell set to 0, so their scripts will never be removed + + // Set OnPCAdd special variable, if it is declared + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex("onpcadd"); + char type = locals.getType("onpcadd"); + + if(index != -1) + { + switch(type) + { + case 's': + item.mRefData->getLocals().mShorts.at (index) = 1; break; + + case 'l': + item.mRefData->getLocals().mLongs.at (index) = 1; break; + + case 'f': + item.mRefData->getLocals().mFloats.at (index) = 1.0; break; + } + } + } else cell = player.getCell(); From c45b4d6072cf5c2fc043089dd1d4c309621d1596 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 22:27:08 -0800 Subject: [PATCH 0202/1483] Clean up some NIF warning reports --- components/nifogre/ogre_nif_loader.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 2da8033e66..8175279d05 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -328,9 +328,14 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); + else + warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } + if(!(node->recType == Nif::RC_NiNode)) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + Nif::ExtraPtr e = node->extra; while(!e.empty()) { @@ -365,9 +370,8 @@ 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::ptr pnif(Nif::NIFFile::create (skel->getName())); - Nif::NIFFile & nif = *pnif.get (); - const Nif::Node *node = dynamic_cast(nif.getRecord(0)); + Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); + const Nif::Node *node = static_cast(nif->getRecord(0)); std::vector ctrls; Ogre::Bone *animroot = NULL; @@ -406,7 +410,7 @@ void loadResource(Ogre::Resource *resource) if(!animroot) { warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ - skel->getName()+", but no text keys. Uses NiBSAnimationNode?"); + skel->getName()+", but no text keys."); return; } @@ -1037,7 +1041,6 @@ public: while(!e.empty()) { Nif::NiStringExtraData *sd; - Nif::NiTextKeyExtraData *td; if((sd=dynamic_cast(e.getPtr())) != NULL) { // String markers may contain important information @@ -1049,12 +1052,6 @@ 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; } @@ -1087,9 +1084,6 @@ public: meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); } - else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && - node->recType != Nif::RC_NiRotatingParticles) - warn("Unhandled mesh node type: "+node->recName); const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) From 007a5963de20e6a123e4d1519e62397a6d385b67 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 23:39:43 -0800 Subject: [PATCH 0203/1483] Handle most state changes in the character controller when setting the movement vector --- apps/openmw/mwmechanics/actors.cpp | 34 ++++----------------------- apps/openmw/mwmechanics/character.cpp | 29 ++++++++++++++++++----- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 27b7ad14e9..2466b8a864 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -211,8 +211,7 @@ namespace MWMechanics float totalDuration = mDuration; mDuration = 0; - PtrControllerMap::iterator iter(mActors.begin()); - while(iter != mActors.end()) + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { @@ -224,10 +223,7 @@ namespace MWMechanics updateNpc(iter->first, totalDuration, paused); if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) - { - iter++; continue; - } } // workaround: always keep player alive for now @@ -244,18 +240,14 @@ namespace MWMechanics } MWWorld::Class::get(iter->first).getCreatureStats(iter->first).resurrect(); - ++iter; continue; } if(iter->second.getState() == CharState_Dead) - { - iter++; continue; - } + iter->second.setMovementVector(Ogre::Vector3::ZERO); iter->second.setState(CharState_Dead, false); - iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -272,26 +264,8 @@ namespace MWMechanics if(iter->second.getState() == CharState_Dead) continue; - Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - CharacterState newstate = CharState_Idle; - - if(dir.length() >= 0.1f) - { - if(std::abs(dir.x/2.0f) > std::abs(dir.y)) - { - if(dir.x > 0.0f) - newstate = CharState_WalkRight; - else if(dir.x < 0.0f) - newstate = CharState_WalkLeft; - } - else if(dir.y < 0.0f) - newstate = CharState_WalkBack; - else - newstate = CharState_WalkForward; - } - - iter->second.setState(newstate, true); - iter->second.setDirection(dir); + Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + iter->second.setMovementVector(movement); } std::vector > movement; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6e78adfa4f..677ffcf239 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -127,14 +127,31 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -void CharacterController::setDirection(const Ogre::Vector3 &dir) +void CharacterController::setMovementVector(const Ogre::Vector3 &vec) { - // HACK: The direction length we get is too large. - float mult = dir.length() / 32.0f; - mult = std::max(1.0f, mult); + // HACK: The length we get is too large. + float speed = std::max(1.0f, vec.length() / 32.0f); + + if(vec.length() >= 0.1f) + { + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + { + if(vec.x > 0.0f) + setState(CharState_WalkRight, true); + else if(vec.x < 0.0f) + setState(CharState_WalkLeft, true); + } + else if(vec.y < 0.0f) + setState(CharState_WalkBack, true); + else + setState(CharState_WalkForward, true); + } + else + setState(CharState_Idle, true); + if(mAnimation) - mAnimation->setSpeedMult(mult); - mDirection = dir.normalisedCopy(); + mAnimation->setSpeedMult(speed); + mDirection = vec.normalisedCopy(); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 53349c841e..e5c7a4b8c0 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -53,7 +53,7 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setDirection(const Ogre::Vector3 &dir); + void setMovementVector(const Ogre::Vector3 &vec); void setState(CharacterState state, bool loop); CharacterState getState() const From 7fe877d8eab4a53dc70f23de52b0fb26493b0d7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 00:19:22 -0800 Subject: [PATCH 0204/1483] Add a couple more character states --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- apps/openmw/mwmechanics/character.cpp | 16 ++++++++++++++-- apps/openmw/mwmechanics/character.hpp | 15 ++++++++++++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2466b8a864..df0d6a5e85 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); else - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Death1, false))); } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -215,7 +215,7 @@ namespace MWMechanics { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) iter->second.setState(CharState_Idle, true); updateActor(iter->first, totalDuration); @@ -243,11 +243,11 @@ namespace MWMechanics continue; } - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) continue; iter->second.setMovementVector(Ogre::Vector3::ZERO); - iter->second.setState(CharState_Dead, false); + iter->second.setState(CharState_Death1, false); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -261,7 +261,7 @@ namespace MWMechanics { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) continue; Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 677ffcf239..4f8525eca2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -37,13 +37,25 @@ static const struct { Ogre::Vector3 accumulate; } sStateList[] = { { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle2, "idle2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle3, "idle3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle4, "idle4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle5, "idle5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle6, "idle6", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle7, "idle7", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle8, "idle8", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle9, "idle9", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, - { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death1, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death2, "death2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death3, "death3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death4, "death4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death5, "death5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, }; static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); @@ -162,7 +174,7 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_Idle || getState() == CharState_Dead)) + if(!(getState() == CharState_Idle || getState() >= CharState_Death1)) { movement = mDirection * movement.length(); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index e5c7a4b8c0..c8e92f7a92 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -15,13 +15,26 @@ namespace MWMechanics enum CharacterState { CharState_Idle, + CharState_Idle2, + CharState_Idle3, + CharState_Idle4, + CharState_Idle5, + CharState_Idle6, + CharState_Idle7, + CharState_Idle8, + CharState_Idle9, CharState_WalkForward, CharState_WalkBack, CharState_WalkLeft, CharState_WalkRight, - CharState_Dead + /* Must be last! */ + CharState_Death1, + CharState_Death2, + CharState_Death3, + CharState_Death4, + CharState_Death5 }; class CharacterController From 60a75cb5ee77453d7d33db421bee3cf2d0eb61f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 00:54:50 -0800 Subject: [PATCH 0205/1483] Make sure to keep the character preview animation updated --- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8f0440b116..24df305566 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -121,7 +121,8 @@ namespace MWRender void InventoryPreview::update(int sizeX, int sizeY) { - mAnimation->forceUpdate (); + mAnimation->runAnimation(0.0f); + mAnimation->forceUpdate(); mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); @@ -145,7 +146,6 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->play("inventoryhandtohand", "start", false); - mAnimation->runAnimation(0.0f); } // -------------------------------------------------------------------------------------------------- From 23acf4b130e10213403b3655dca97eeb13f5808b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 01:38:42 -0800 Subject: [PATCH 0206/1483] Don't break right away when the animation time remaining is 0 --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b811040676..0e906181c5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -225,7 +225,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) Ogre::Vector3 movement = Ogre::Vector3::ZERO; timepassed *= mAnimSpeedMult; - while(mCurrentAnim && mPlaying && timepassed > 0.0f) + while(mCurrentAnim && mPlaying) { float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 165a6525c3..46a1ed88d2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -44,6 +44,7 @@ protected: * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); @@ -52,6 +53,7 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); + void createEntityList(Ogre::SceneNode *node, const std::string &model); public: From d6a73a2a02d4d49bb733a59d8e1442ed819d831c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 Feb 2013 11:41:31 +0100 Subject: [PATCH 0207/1483] updated changelog --- readme.txt | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/readme.txt b/readme.txt index d94ccd7f08..91690ff574 100644 --- a/readme.txt +++ b/readme.txt @@ -94,6 +94,38 @@ Allowed options: CHANGELOG +0.21.0 + +Bug #253: Dialogs don't work for Russian version of Morrowind +Bug #267: Activating creatures without dialogue can still activate the dialogue GUI +Bug #354: True flickering lights +Bug #386: The main menu's first entry is wrong (in french) +Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations +Bug #495: Activation Range +Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned +Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available +Bug #500: Disposition for most NPCs is 0/100 +Bug #501: Getdisposition command wrongly returns base disposition +Bug #506: Journal UI doesn't update anymore +Bug #507: EnableRestMenu is not a valid command - change it to EnableRest +Bug #508: Crash in Ald Daedroth Shrine +Bug #517: Wrong price calculation when untrading an item +Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin +Bug #524: Beast races are able to wear shoes +Bug #527: Background music fails to play +Bug #533: The arch at Gnisis entrance is not displayed +Bug #536: The same entry can be added multiple times to the journal +Bug #539: Race selection is broken +Feature #39: Video Playback +Feature #151: ^-escape sequences in text output +Feature #392: Add AI related script functions +Feature #456: Determine required ini fallback values and adjust the ini importer accordingly +Feature #460: Experimental DirArchives improvements +Feature #540: Execute scripts of objects in containers/inventories in active cells +Task #401: Review GMST fixing +Task #453: Unify case smashing/folding +Task #512: Rewrite utf8 component + 0.20.0 Bug #366: Changing the player's race during character creation does not change the look of the player character From a4872e321717ca7f3017bf5bbcbe36d2e8232da1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 Feb 2013 13:30:40 +0100 Subject: [PATCH 0208/1483] rewrote the opencs cmake scripts (more compact and no more annoying warnings) --- apps/opencs/CMakeLists.txt | 101 ++++++++++++++++++++++++------------- cmake/OpenMWMacros.cmake | 48 ++++++++++++++++++ 2 files changed, 113 insertions(+), 36 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index abbc953ca4..d1cfbea524 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -1,46 +1,75 @@ -set (OPENCS_SRC - main.cpp editor.cpp +set (OPENCS_SRC main.cpp) - model/doc/documentmanager.cpp model/doc/document.cpp +opencs_units (. editor) - model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp - model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp - model/world/columnbase.cpp - model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp - model/tools/mandatoryid.cpp model/tools/reportmodel.cpp - - view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp - view/doc/subview.cpp - - view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp - view/world/dialoguesubview.cpp - - view/tools/reportsubview.cpp view/tools/subviews.cpp +opencs_units (model/doc + document ) -set (OPENCS_HDR - editor.hpp - - model/doc/documentmanager.hpp model/doc/document.hpp model/doc/state.hpp - - model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp - model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp - model/world/commands.hpp model/world/columnbase.hpp - - model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp - model/tools/mandatoryid.hpp model/tools/reportmodel.hpp - - view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp - view/doc/subview.hpp view/doc/subviewfactoryimp.hpp - - view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp - view/world/dialoguesubview.hpp - - view/tools/reportsubview.hpp view/tools/subviews.hpp +opencs_units_noqt (model/doc + documentmanager ) +opencs_hdrs_noqt (model/doc + state + ) + + +opencs_units (model/world + idtable idtableproxymodel + ) + +opencs_units_noqt (model/world + universalid data record idcollection commands columnbase + ) + +opencs_hdrs_noqt (model/world + columns + ) + + +opencs_units (model/tools + tools operation reportmodel + ) + +opencs_units_noqt (model/tools + stage verifier mandatoryid + ) + + +opencs_units (view/doc + viewmanager view operations operation subview + ) + +opencs_units_noqt (view/doc + subviewfactory + ) + +opencs_hdrs_noqt (view/doc + subviewfactoryimp + ) + + +opencs_units (view/world + table tablesubview + ) + +opencs_units_noqt (view/world + dialoguesubview util subviews + ) + + +opencs_units (view/tools + reportsubview + ) + +opencs_units_noqt (view/tools + subviews + ) + + set (OPENCS_US ) @@ -57,7 +86,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED) include(${QT_USE_FILE}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) -qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR}) +qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index e6f45fdb1f..d13568a688 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -29,3 +29,51 @@ get_filename_component(filename ${f} NAME) configure_file(${source_dir}/${f} ${destination_dir}/${filename} COPYONLY) endforeach (f) endmacro (copy_all_files) + +macro (add_file project type file) +list (APPEND ${project}${type} ${file}) +endmacro (add_file) + +macro (add_unit project dir unit) +add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") +add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp") +endmacro (add_unit) + +macro (add_qt_unit project dir unit) +add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") +add_file (${project} _HDR_QT ${comp} "${dir}/${unit}.hpp") +add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp") +endmacro (add_qt_unit) + +macro (add_hdr project dir unit) +add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") +endmacro (add_hdr) + +macro (add_qt_hdr project dir unit) +add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") +add_file (${project} _HDR_QT ${comp} "${dir}/${unit}.hpp") +endmacro (add_qt_hdr) + +macro (opencs_units dir) +foreach (u ${ARGN}) +add_qt_unit (OPENCS ${dir} ${u}) +endforeach (u) +endmacro (opencs_units) + +macro (opencs_units_noqt dir) +foreach (u ${ARGN}) +add_unit (OPENCS ${dir} ${u}) +endforeach (u) +endmacro (opencs_units) + +macro (opencs_hdrs dir) +foreach (u ${ARGN}) +add_qt_hdr (OPENCS ${dir} ${u}) +endforeach (u) +endmacro (opencs_hdrs) + +macro (opencs_hdrs_noqt dir) +foreach (u ${ARGN}) +add_hdr (OPENCS ${dir} ${u}) +endforeach (u) +endmacro (opencs_hdrs) From c97553703a6f11d82d0e3c11bc2311ae5a1cb4d1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 Feb 2013 13:47:55 +0100 Subject: [PATCH 0209/1483] fixes for static build without cg --- apps/openmw/CMakeLists.txt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090c..e2cb0e5c41 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -72,15 +72,20 @@ add_openmw_dir (mwbase ) # Main executable + IF(OGRE_STATIC) +ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) +set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) IF(WIN32) -ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager -DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL) -set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) -ELSE(WIN32) -ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager -DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) -set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${Cg_LIBRARIES} ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) +ADD_DEFINITIONS(-DENABLE_PLUGIN_Direct3D9) +list (APPEND OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_Direct3D9_LIBRARIES}) ENDIF(WIN32) +IF (Cg_FOUND) +ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager) +list (APPEND OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${Cg_LIBRARIES}) +ENDIF (Cg_FOUND) ENDIF(OGRE_STATIC) + add_executable(openmw ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} From ac112ef972927e96879405edca9aaf7c058440aa Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 3 Feb 2013 13:27:27 +0000 Subject: [PATCH 0210/1483] refactored special variable code --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 24 ++------------- apps/openmw/mwscript/locals.cpp | 41 ++++++++++++++++++++++++++ apps/openmw/mwscript/locals.hpp | 21 +++++-------- apps/openmw/mwworld/actionequip.cpp | 21 +------------ apps/openmw/mwworld/containerstore.cpp | 21 ++----------- apps/openmw/mwworld/worldimp.cpp | 22 ++------------ 7 files changed, 58 insertions(+), 94 deletions(-) create mode 100644 apps/openmw/mwscript/locals.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090c..f61f5ead28 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,7 +41,7 @@ add_openmw_dir (mwscript locals scriptmanagerimp compilercontext interpretercontext cellextensions miscextensions guiextensions soundextensions skyextensions statsextensions containerextensions aiextensions controlextensions extensions globalscripts ref dialogueextensions - animationextensions transformationextensions consoleextensions userextensions + animationextensions transformationextensions consoleextensions userextensions locals ) add_openmw_dir (mwsound diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ebbd69d80b..40771af166 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -13,7 +13,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/scriptmanager.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -245,27 +244,10 @@ namespace MWGui invStore.equip(slot, invStore.end()); std::string script = MWWorld::Class::get(*it).getScript(*it); - /* Unset OnPCEquip Variable on item's script, if it has a script with that variable declared */ + // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared if(script != "") - { - Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); - int index = locals.getIndex("onpcequip"); - char type = locals.getType("onpcequip"); - if(index != -1) - { - switch(type) - { - case 's': - (*it).mRefData->getLocals().mShorts.at (index) = 0; break; - - case 'l': - (*it).mRefData->getLocals().mLongs.at (index) = 0; break; - - case 'f': - (*it).mRefData->getLocals().mFloats.at (index) = 0.0; break; - } - } - } + (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 0); + return; } } diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp new file mode 100644 index 0000000000..53f744323e --- /dev/null +++ b/apps/openmw/mwscript/locals.cpp @@ -0,0 +1,41 @@ +#include "locals.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/scriptmanager.hpp" +#include + +namespace MWScript +{ + void Locals::configure (const ESM::Script& script) + { + mShorts.clear(); + mShorts.resize (script.mData.mNumShorts, 0); + mLongs.clear(); + mLongs.resize (script.mData.mNumLongs, 0); + mFloats.clear(); + mFloats.resize (script.mData.mNumFloats, 0); + } + + bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) + { + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex(var); + char type = locals.getType(var); + if(index != -1) + { + switch(type) + { + case 's': + mShorts.at (index) = val; break; + + case 'l': + mLongs.at (index) = val; break; + + case 'f': + mFloats.at (index) = val; break; + } + return true; + } + return false; + } +} diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index ec02e2f126..e933c727f3 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -8,21 +8,16 @@ namespace MWScript { - struct Locals + class Locals { - std::vector mShorts; - std::vector mLongs; - std::vector mFloats; + public: + std::vector mShorts; + std::vector mLongs; + std::vector mFloats; + + void configure (const ESM::Script& script); + bool setVarByInt(const std::string& script, const std::string& var, int val); - void configure (const ESM::Script& script) - { - mShorts.clear(); - mShorts.resize (script.mData.mNumShorts, 0); - mLongs.clear(); - mLongs.resize (script.mData.mNumLongs, 0); - mFloats.clear(); - mFloats.resize (script.mData.mNumFloats, 0); - } }; } diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 2b238ead99..b1236f829a 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -3,7 +3,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/scriptmanager.hpp" #include @@ -113,24 +112,6 @@ namespace MWWorld /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") - { - Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); - int index = locals.getIndex("onpcequip"); - char type = locals.getType("onpcequip"); - if(index != -1) - { - switch(type) - { - case 's': - (*it).mRefData->getLocals().mShorts.at (index) = 1; break; - - case 'l': - (*it).mRefData->getLocals().mLongs.at (index) = 1; break; - - case 'f': - (*it).mRefData->getLocals().mFloats.at (index) = 1.0; break; - } - } - } + (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 31eabb3424..eb2a14d5b8 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -88,27 +88,10 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) { - cell = 0; // Items in players inventory have cell set to 0, so their scripts will never be removed + cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed // Set OnPCAdd special variable, if it is declared - Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); - int index = locals.getIndex("onpcadd"); - char type = locals.getType("onpcadd"); - - if(index != -1) - { - switch(type) - { - case 's': - item.mRefData->getLocals().mShorts.at (index) = 1; break; - - case 'l': - item.mRefData->getLocals().mLongs.at (index) = 1; break; - - case 'f': - item.mRefData->getLocals().mFloats.at (index) = 1.0; break; - } - } + item.mRefData->getLocals().setVarByInt(script, "onpcadd", 1); } else cell = player.getCell(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0c8027975b..2926b76f8b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1277,27 +1277,9 @@ namespace MWWorld { std::string script = MWWorld::Class::get(item).getScript(item); - /* Set OnPCDrop Variable on item's script, if it has a script with that variable declared */ + // Set OnPCDrop Variable on item's script, if it has a script with that variable declared if(script != "") - { - Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); - int index = locals.getIndex("onpcdrop"); - char type = locals.getType("onpcdrop"); - if(index != -1) - { - switch(type) - { - case 's': - item.mRefData->getLocals().mShorts.at (index) = 1; break; - - case 'l': - item.mRefData->getLocals().mLongs.at (index) = 1; break; - - case 'f': - item.mRefData->getLocals().mFloats.at (index) = 1.0; break; - } - } - } + item.mRefData->getLocals().setVarByInt(script, "onpcdrop", 1); } bool World::placeObject (const Ptr& object, float cursorX, float cursorY) From 15e51b76de89c8366d6573700f63f6f6290c7e3d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 15:46:23 +0100 Subject: [PATCH 0211/1483] Experimental: Directional shading on local map, separated out refraction render, no longer uses screen depth --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 9 ++-- apps/openmw/mwrender/localmap.cpp | 34 +++++++++---- apps/openmw/mwrender/localmap.hpp | 9 +++- apps/openmw/mwrender/npcanimation.cpp | 6 ++- apps/openmw/mwrender/occlusionquery.cpp | 7 ++- apps/openmw/mwrender/occlusionquery.hpp | 8 +++ apps/openmw/mwrender/refraction.cpp | 62 +++++++++++++++++++++++ apps/openmw/mwrender/refraction.hpp | 36 +++++++++++++ apps/openmw/mwrender/renderconst.hpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 53 ++++++++++++------- apps/openmw/mwrender/renderingmanager.hpp | 8 +-- apps/openmw/mwrender/ripplesimulation.cpp | 11 ++-- apps/openmw/mwrender/ripplesimulation.hpp | 3 -- apps/openmw/mwrender/sky.cpp | 4 ++ apps/openmw/mwrender/sky.hpp | 1 + apps/openmw/mwrender/water.cpp | 34 +++++++++---- apps/openmw/mwrender/water.hpp | 5 +- apps/openmw/mwworld/weather.cpp | 4 +- extern/shiny/Main/Factory.cpp | 2 - files/materials/openmw.configuration | 1 - files/materials/water.mat | 2 +- files/materials/water.shader | 22 ++------ libs/openengine/ogre/renderer.cpp | 13 +++++ 25 files changed, 250 insertions(+), 92 deletions(-) create mode 100644 apps/openmw/mwrender/refraction.cpp create mode 100644 apps/openmw/mwrender/refraction.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2c49e848ec..94952329ec 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows - compositors characterpreview externalrendering globalmap videoplayer ripplesimulation + compositors characterpreview externalrendering globalmap videoplayer ripplesimulation refraction ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index dd5289edb1..8fecf4c34b 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -150,7 +150,7 @@ namespace MWGui if (!mFirstLoad) { mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName()); - mRectangle->setVisible(true); + //mRectangle->setVisible(true); } for (unsigned int i = 0; igetNumCompositors(); ++i) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index a172d02b1c..704d0b6fd1 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -59,7 +59,7 @@ namespace MWRender mNode = renderRoot->createChildSceneNode(); mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), RV_PlayerPreview); + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0); mNode->setVisible (false); @@ -81,7 +81,6 @@ namespace MWRender mViewport->setOverlaysEnabled(false); mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); mViewport->setShadowsEnabled(false); - mViewport->setVisibilityMask (RV_PlayerPreview); mRenderTarget->setActive(true); mRenderTarget->setAutoUpdated (false); @@ -102,7 +101,7 @@ namespace MWRender delete mAnimation; mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), RV_PlayerPreview); + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0); mNode->setVisible (false); @@ -118,6 +117,7 @@ namespace MWRender InventoryPreview::InventoryPreview(MWWorld::Ptr character) : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 65, -180), Ogre::Vector3(0,65,0)) + , mSelectionBuffer(NULL) { } @@ -149,7 +149,8 @@ namespace MWRender void InventoryPreview::onSetup () { - mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); + if (!mSelectionBuffer) + mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); mAnimation->playGroup ("inventoryhandtohand", 0, 1); mAnimation->runAnimation (0); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b34942d28e..1d338df122 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -32,6 +32,12 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0)); mCameraNode->attachObject(mCellCamera); + + mLight = mRendering->getScene()->createLight(); + mLight->setType (Ogre::Light::LT_DIRECTIONAL); + mLight->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLight->setVisible (false); + mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); } LocalMap::~LocalMap() @@ -181,17 +187,14 @@ void LocalMap::render(const float x, const float y, const float zlow, const float zhigh, const float xw, const float yw, const std::string& texture) { - // disable fog - // changing FOG_MODE is not a solution when using shaders, thus we have to push linear start/end + // disable fog (only necessary for fixed function, the shader based + // materials already do this through local_map material configuration) const float fStart = mRendering->getScene()->getFogStart(); const float fEnd = mRendering->getScene()->getFogEnd(); const ColourValue& clr = mRendering->getScene()->getFogColour(); - mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, 1000000, 10000000); + mRendering->getScene()->setFog(FOG_NONE); // make everything visible - mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); - mRenderingManager->disableLights(); - mCameraNode->setPosition(Vector3(x, zhigh+100000, y)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite @@ -231,7 +234,8 @@ void LocalMap::render(const float x, const float y, // use fallback techniques without shadows and without mrt vp->setMaterialScheme("local_map"); - rtt->update(); + rtt->setAutoUpdated(true); + rtt->addListener(this); // create "fog of war" texture TexturePtr tex2 = TextureManager::getSingleton().createManual( @@ -263,12 +267,24 @@ void LocalMap::render(const float x, const float y, } } - mRenderingManager->enableLights(); - // re-enable fog mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd); } +void LocalMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) +{ + mRenderingManager->disableLights(true); + mLight->setVisible(true); + evt.source->setAutoUpdated(false); +} + +void LocalMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) +{ + mRenderingManager->enableLights(true); + mLight->setVisible(false); + evt.source->removeListener(this); +} + void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) { pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle); diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 1aedf13255..2b1aa3f625 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace MWWorld { @@ -17,7 +18,7 @@ namespace MWRender /// /// \brief Local map rendering /// - class LocalMap + class LocalMap : public Ogre::RenderTargetListener { public: LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering); @@ -69,6 +70,9 @@ namespace MWRender */ bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + private: OEngine::Render::OgreRenderer* mRendering; MWRender::RenderingManager* mRenderingManager; @@ -90,6 +94,9 @@ namespace MWRender Ogre::SceneNode* mCameraPosNode; Ogre::SceneNode* mCameraRotNode; + // directional light from a fixed angle + Ogre::Light* mLight; + float mAngle; const Ogre::Vector2 rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d33bdda91d..52ad24523f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -95,7 +95,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->getUserObjectBindings ().setUserAny (Ogre::Any(-1)); - base->setVisibilityFlags(mVisibilityFlags); + if (mVisibilityFlags != 0) + base->setVisibilityFlags(mVisibilityFlags); bool transparent = false; for(unsigned int j=0;j < base->getNumSubEntities();++j) { @@ -362,7 +363,8 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) { - parts[i]->setVisibilityFlags(mVisibilityFlags); + if (mVisibilityFlags != 0) + parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->getUserObjectBindings ().setUserAny (Ogre::Any(group)); } return entities; diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 6d3f67de96..c9e649fe6f 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -16,7 +16,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0), mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false), - mBBNode(0) + mBBNode(0), mActive(false) { mRendering = renderer; mSunNode = sunNode; @@ -108,8 +108,9 @@ bool OcclusionQuery::supported() void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, const LightList* pLightList, bool suppressRenderStateChanges) { + if (!mActive) return; // The following code activates and deactivates the occlusion queries - // so that the queries only include the rendering of their intended targets + // so that the queries only include the rendering of the intended meshes // Close the last occlusion query // Each occlusion query should only last a single rendering @@ -146,6 +147,8 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation) { + if (!mActive) return; + if (mActiveQuery != NULL) { mActiveQuery->endOcclusionQuery(); diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index c76fcccd08..af6f668c17 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -29,6 +29,12 @@ namespace MWRender */ bool supported(); + /** + * make sure to disable occlusion queries before updating unrelated render targets + * @param active + */ + void setActive (bool active) { mActive = active; } + /** * per-frame update */ @@ -85,6 +91,8 @@ namespace MWRender bool mTestResult; + bool mActive; + bool mSupported; bool mDoQuery; bool mDoQuery2; diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp new file mode 100644 index 0000000000..175b852238 --- /dev/null +++ b/apps/openmw/mwrender/refraction.cpp @@ -0,0 +1,62 @@ +#include "refraction.hpp" + +#include +#include +#include +#include +#include +#include + +#include "renderconst.hpp" + +namespace MWRender +{ + + Refraction::Refraction(Ogre::Camera *parentCamera) + : mParentCamera(parentCamera) + { + mCamera = mParentCamera->getSceneManager()->createCamera("RefractionCamera"); + + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("WaterRefraction", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); + + mRenderTarget = texture->getBuffer()->getRenderTarget(); + Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain); + mRenderTarget->setAutoUpdated(true); + mRenderTarget->addListener(this); + } + + Refraction::~Refraction() + { + Ogre::TextureManager::getSingleton().remove("WaterRefraction"); + mParentCamera->getSceneManager()->destroyCamera(mCamera); + mRenderTarget->removeListener(this); + } + + void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) + { + mParentCamera->getParentSceneNode ()->needUpdate (); + mCamera->setOrientation(mParentCamera->getDerivedOrientation()); + mCamera->setPosition(mParentCamera->getDerivedPosition()); + mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); + mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); + mCamera->setAspectRatio(mParentCamera->getAspectRatio()); + mCamera->setFOVy(mParentCamera->getFOVy()); + + mCamera->enableCustomNearClipPlane(mNearClipPlane); + } + + void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) + { + + } + + void Refraction::setWaterPlane(Ogre::Plane plane) + { + mNearClipPlane = Ogre::Plane(-plane.normal, - (plane.d + 5) ); + } + +} diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp new file mode 100644 index 0000000000..01ec86521a --- /dev/null +++ b/apps/openmw/mwrender/refraction.hpp @@ -0,0 +1,36 @@ +#ifndef MWRENDER_REFRACTION_H +#define MWRENDER_REFRACTION_H + +#include +#include + +namespace Ogre +{ + class Camera; + class RenderTarget; +} + +namespace MWRender +{ + + class Refraction : public Ogre::RenderTargetListener + { + + public: + Refraction(Ogre::Camera* parentCamera); + ~Refraction(); + + void setWaterPlane (Ogre::Plane plane); + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + + private: + Ogre::Camera* mParentCamera; + Ogre::Camera* mCamera; + Ogre::RenderTarget* mRenderTarget; + Ogre::Plane mNearClipPlane; + }; + +} + +#endif diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 75e243ec79..ee7e023a1b 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -54,9 +54,7 @@ enum VisibilityFlags RV_OcclusionQuery = 256, - RV_PlayerPreview = 512, - - RV_Debug = 1024, + RV_Debug = 512, RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3fed4d9944..18337c7d78 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -334,8 +334,13 @@ void RenderingManager::update (float duration, bool paused) mPlayer->setCameraDistance(test.second * orig.distance(dest), false, false); } } + mOcclusionQuery->update(duration); - + + // deactivate queries to make sure we aren't getting false results from several misc render targets + // (will be reactivated at the bottom of this method) + mOcclusionQuery->setActive(false); + mVideoPlayer->update (); mRendering.update(duration); @@ -391,6 +396,8 @@ void RenderingManager::update (float duration, bool paused) orig = Ogre::Vector3(orig.x, orig.z, -orig.y); mWater->update(duration, orig); } + + mOcclusionQuery->setActive(true); } void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) @@ -608,22 +615,28 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) mTerrainManager->setAmbient(colour); } -void RenderingManager::sunEnable() +void RenderingManager::sunEnable(bool real) { - // Don't disable the light, as the shaders assume the first light to be directional. - //if (mSun) mSun->setVisible(true); - mSunEnabled = true; + if (real && mSun) mSun->setVisible(true); + else + { + // Don't disable the light, as the shaders assume the first light to be directional. + mSunEnabled = true; + } } -void RenderingManager::sunDisable() +void RenderingManager::sunDisable(bool real) { - // Don't disable the light, as the shaders assume the first light to be directional. - //if (mSun) mSun->setVisible(false); - mSunEnabled = false; - if (mSun) + if (real && mSun) mSun->setVisible(false); + else { - mSun->setDiffuseColour(ColourValue(0,0,0)); - mSun->setSpecularColour(ColourValue(0,0,0)); + // Don't disable the light, as the shaders assume the first light to be directional. + mSunEnabled = false; + if (mSun) + { + mSun->setDiffuseColour(ColourValue(0,0,0)); + mSun->setSpecularColour(ColourValue(0,0,0)); + } } } @@ -654,16 +667,16 @@ void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell) mLocalMap->saveFogOfWar(cell); } -void RenderingManager::disableLights() +void RenderingManager::disableLights(bool sun) { mObjects.disableLights(); - sunDisable(); + sunDisable(sun); } -void RenderingManager::enableLights() +void RenderingManager::enableLights(bool sun) { mObjects.enableLights(); - sunEnable(); + sunEnable(sun); } const bool RenderingManager::useMRT() @@ -867,14 +880,16 @@ void RenderingManager::applyCompositors() mCompositors->removeAll(); if (useMRT()) { + /* mCompositors->addCompositor("gbuffer", 0); mCompositors->setCompositorEnabled("gbuffer", true); mCompositors->addCompositor("gbufferFinalizer", 2); mCompositors->setCompositorEnabled("gbufferFinalizer", true); - } + */ +} - if (mWater) - mWater->assignTextures(); + //if (mWater) + //mWater->assignTextures(); } void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 68f2d79c37..0a92bb2ea8 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -131,11 +131,11 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setAmbientColour(const Ogre::ColourValue& colour); void setSunColour(const Ogre::ColourValue& colour); void setSunDirection(const Ogre::Vector3& direction); - void sunEnable(); - void sunDisable(); + void sunEnable(bool real); ///< @param real whether or not to really disable the sunlight (otherwise just set diffuse to 0) + void sunDisable(bool real); - void disableLights(); - void enableLights(); + void disableLights(bool sun); ///< @param sun whether or not to really disable the sunlight (otherwise just set diffuse to 0) + void enableLights(bool sun); bool occlusionQuerySupported() { return mOcclusionQuery->supported(); } OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; } diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 6096c7ba34..043757e885 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -25,10 +25,6 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); - - mHeightToNormalMapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightToNormalMap"); - mHeightmapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightmapSimulation"); - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); mCamera = mSceneMgr->createCamera("RippleCamera"); @@ -46,7 +42,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); impulseNode->attachObject(mImpulse); - float w=0.05; + //float w=0.05; for (int i=0; i<4; ++i) { Ogre::TexturePtr texture; @@ -65,11 +61,11 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) rt->getViewport(0)->setClearEveryFrame(false); // debug overlay + /* Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true); debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false); w += 0.2; debugOverlay->setBoundingBox(aabInf); - Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode(); debugNode->attachObject(debugOverlay); @@ -83,6 +79,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i)); + */ mRenderTargets[i] = rt; mTextures[i] = texture; @@ -126,8 +123,6 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) // texture coordinate space mCurrentFrameOffset /= mRippleAreaLength; - std::cout << "Offset " << mCurrentFrameOffset << std::endl; - mRippleCenter = position; addImpulses(); diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 6096fa866c..72ff3dbd81 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -43,9 +43,6 @@ private: // scenemanager to create the debug overlays on Ogre::SceneManager* mMainSceneMgr; - Ogre::MaterialPtr mHeightmapMaterial; - Ogre::MaterialPtr mHeightToNormalMapMaterial; - static const int TEX_NORMAL = 3; Ogre::Rectangle2D* mImpulse; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 60ecd43034..91277ebf66 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -628,6 +628,10 @@ void SkyManager::setLightningStrength(const float factor) else mLightning->setVisible(false); } +void SkyManager::setLightningEnabled(bool enabled) +{ + /// \todo +} void SkyManager::setLightningDirection(const Ogre::Vector3& dir) { diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index ee13608531..04d56d4af2 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -167,6 +167,7 @@ namespace MWRender void setLightningStrength(const float factor); void setLightningDirection(const Ogre::Vector3& dir); + void setLightningEnabled(bool enabled); ///< disable prior to map render void setGlare(const float glare); void setGlareEnabled(bool enabled); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 6ee3890dda..0533388bca 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -13,6 +13,7 @@ #include "renderingmanager.hpp" #include "compositors.hpp" #include "ripplesimulation.hpp" +#include "refraction.hpp" #include #include @@ -85,7 +86,7 @@ PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* s mSceneMgr->addRenderQueueListener(this); mTexture = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_A8R8G8B8, TU_RENDERTARGET); + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET); mRenderTarget = mTexture->getBuffer()->getRenderTarget(); Viewport* vp = mRenderTarget->addViewport(mCamera); @@ -96,6 +97,7 @@ PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* s vp->setMaterialScheme("water_reflection"); mRenderTarget->addListener(this); mRenderTarget->setActive(true); + mRenderTarget->setAutoUpdated(true); sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName()); } @@ -104,6 +106,7 @@ PlaneReflection::~PlaneReflection () { mRenderTarget->removeListener (this); mSceneMgr->destroyCamera (mCamera); + mSceneMgr->removeRenderQueueListener(this); TextureManager::getSingleton ().remove("WaterReflection"); } @@ -127,7 +130,7 @@ void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::St } } -void PlaneReflection::preRenderTargetUpdate(const RenderTargetEvent& evt) +void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { mParentCamera->getParentSceneNode ()->needUpdate (); mCamera->setOrientation(mParentCamera->getDerivedOrientation()); @@ -144,7 +147,7 @@ void PlaneReflection::preRenderTargetUpdate(const RenderTargetEvent& evt) mCamera->enableReflection(mWaterPlane); } -void PlaneReflection::postRenderTargetUpdate(const RenderTargetEvent& evt) +void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { mSky->resetSkyPosition(); mCamera->disableReflection(); @@ -232,7 +235,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); m->setListener (this); - // ---------------------------------------------------------------------------------------------- // ---------------------------------- reflection debug overlay ---------------------------------- // ---------------------------------------------------------------------------------------------- @@ -296,6 +298,9 @@ Water::~Water() mWaterNode->detachObject(mWater); mSceneMgr->destroyEntity(mWater); mSceneMgr->destroySceneNode(mWaterNode); + + delete mReflection; + delete mRefraction; } void Water::changeCell(const ESM::Cell* cell) @@ -316,6 +321,8 @@ void Water::setHeight(const float height) if (mReflection) mReflection->setWaterPlane(mWaterPlane); + if (mRefraction) + mRefraction->setWaterPlane(mWaterPlane); mWaterNode->setPosition(0, height, 0); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); @@ -353,7 +360,7 @@ void Water::assignTextures() { if (Settings::Manager::getBool("shader", "Water")) { - +/* CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mRendering->getViewport())->getCompositor("gbuffer"); TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); @@ -361,6 +368,7 @@ void Water::assignTextures() TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1); sh::Factory::getInstance ().setTextureAlias ("SceneDepth", depthTexture->getName()); + */ } } @@ -397,15 +405,15 @@ void Water::update(float dt, Ogre::Vector3 player) mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); + + if (mReflection) + mReflection->update(); } void Water::applyRTT() { - if (mReflection) - { - delete mReflection; - mReflection = NULL; - } + delete mReflection; + mReflection = NULL; // Create rendertarget for reflection int rttsize = Settings::Manager::getInt("rtt size", "Water"); @@ -419,6 +427,12 @@ void Water::applyRTT() } else mWater->setRenderQueueGroup(RQG_Alpha); + + + delete mRefraction; + mRefraction = NULL; + + mRefraction = new Refraction(mCamera); } void Water::applyVisibilityMask() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 97eb590b3d..67c788c817 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,12 +30,14 @@ namespace MWRender { class SkyManager; class RenderingManager; class RippleSimulation; + class Refraction; class Reflection { public: Reflection(Ogre::SceneManager* sceneManager) : mSceneMgr(sceneManager) {} + virtual ~Reflection() {} virtual void setWaterPlane (Ogre::Plane plane) {} virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } @@ -111,7 +113,6 @@ namespace MWRender { float mWaterTimer; - RippleSimulation* mSimulation; Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); @@ -132,6 +133,8 @@ namespace MWRender { int mVisibilityFlags; Reflection* mReflection; + Refraction* mRefraction; + RippleSimulation* mSimulation; public: Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 917a8d7d46..514276f9bc 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -718,14 +718,14 @@ void WeatherManager::update(float duration) mRendering->getSkyManager()->setLightningStrength(0.f); mRendering->setAmbientColour(result.mAmbientColor); - mRendering->sunEnable(); + mRendering->sunEnable(false); mRendering->setSunColour(result.mSunColor); mRendering->getSkyManager()->setWeather(result); } else { - mRendering->sunDisable(); + mRendering->sunDisable(false); mRendering->skyDisable(); mRendering->getSkyManager()->setLightningStrength(0.f); } diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 6e87800e5e..82d6648110 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -219,8 +219,6 @@ namespace sh break; } - std::cout << "loading " << it->first << std::endl; - MaterialInstance newInstance(it->first, this); newInstance.create(mPlatform); if (!mShadersEnabled) diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index ee97451d39..db3693dd66 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -10,7 +10,6 @@ configuration local_map { fog false mrt_output false - lighting false shadows false shadows_pssm false simple_water true diff --git a/files/materials/water.mat b/files/materials/water.mat index c427447d24..2717f26fcb 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -20,7 +20,7 @@ material Water texture_unit refractionMap { - texture_alias WaterRefraction + direct_texture WaterRefraction tex_address_mode clamp } diff --git a/files/materials/water.shader b/files/materials/water.shader index 1e14dd5962..dbe36a91ce 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -201,13 +201,9 @@ SH_START_PROGRAM { - float2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1-shSaturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; - float depth = shSample(depthMap, screenCoords).x * far - depthPassthrough; - float shoreFade = shSaturate(depth / 50.0); - float2 nCoord = float2(0,0); nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); @@ -272,14 +268,8 @@ // refraction float3 R = reflect(vVec, normal); - - // check the depth at the refracted coords, and don't do any normal distortion for the refraction if the object to refract - // is actually above the water (objectDepth < waterDepth) - // this solves silhouettes around objects above the water - float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xz*REFR_BUMP)).x * far - depthPassthrough; - float doRefraction = (refractDepth < 0) ? 0.f : 1.f; - - float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(shoreFade * normal.xz*REFR_BUMP * doRefraction))*1.0).rgb); + + float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(normal.xz*REFR_BUMP))*1.0).rgb); // brighten up the refraction underwater refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction; @@ -288,10 +278,7 @@ float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; - - // smooth transition to shore (above water only) - shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, refraction, (1-shoreFade) * (1-isUnderwater)); - + // fog if (isUnderwater == 1) { @@ -319,8 +306,7 @@ } shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); - //shOutputColour(0).xyz = float3(relPos.x, relPos.y, 0); - shOutputColour(0).w = 1; + shOutputColour(0).w = 1; } #endif diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index ed5cc9b435..e6e1d46b85 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -210,11 +210,24 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& assert(mRoot); mRoot->initialise(false); + // create a hidden 1x1 background window to keep resources when recreating the secondary (real) window + /// \todo Why does this break occlusion queries? :( + /* + NameValuePairList params_; + params_.insert(std::make_pair("title", title)); + params_.insert(std::make_pair("FSAA", "0")); + params_.insert(std::make_pair("vsync", "false")); + params_.insert(std::make_pair("hidden", "true")); + Ogre::RenderWindow* hiddenWindow = mRoot->createRenderWindow("InactiveHidden", 1, 1, false, ¶ms_); + hiddenWindow->setActive(false); + */ + NameValuePairList params; params.insert(std::make_pair("title", title)); params.insert(std::make_pair("FSAA", settings.fsaa)); params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); + mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); // create the semi-transparent black background texture used by the GUI. From 51d5efeeb2df6a4be1b0c94df9a54011e60ddb2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 07:15:34 -0800 Subject: [PATCH 0212/1483] Work out the state in the character controller update method --- apps/openmw/mwmechanics/actors.cpp | 10 -------- apps/openmw/mwmechanics/character.cpp | 35 +++++++++++++-------------- apps/openmw/mwmechanics/character.hpp | 2 -- 3 files changed, 17 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index df0d6a5e85..c1f552ae49 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -246,7 +246,6 @@ namespace MWMechanics if(iter->second.getState() >= CharState_Death1) continue; - iter->second.setMovementVector(Ogre::Vector3::ZERO); iter->second.setState(CharState_Death1, false); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -259,15 +258,6 @@ namespace MWMechanics if(!paused) { - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - { - if(iter->second.getState() >= CharState_Death1) - continue; - - Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - iter->second.setMovementVector(movement); - } - std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4f8525eca2..f5a4dda51b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -139,36 +139,35 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -void CharacterController::setMovementVector(const Ogre::Vector3 &vec) +Ogre::Vector3 CharacterController::update(float duration) { + const MWWorld::Class &cls = MWWorld::Class::get(mPtr); + const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + // HACK: The length we get is too large. float speed = std::max(1.0f, vec.length() / 32.0f); - if(vec.length() >= 0.1f) + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) - { - if(vec.x > 0.0f) - setState(CharState_WalkRight, true); - else if(vec.x < 0.0f) - setState(CharState_WalkLeft, true); - } - else if(vec.y < 0.0f) - setState(CharState_WalkBack, true); - else - setState(CharState_WalkForward, true); + if(vec.x > 0.0f) + setState(CharState_WalkRight, true); + else if(vec.x < 0.0f) + setState(CharState_WalkLeft, true); } + else if(vec.y > 0.0f) + setState(CharState_WalkForward, true); + else if(vec.y < 0.0f) + setState(CharState_WalkBack, true); else - setState(CharState_Idle, true); + { + if(!(getState() >= CharState_Death1)) + setState(CharState_Idle, true); + } if(mAnimation) mAnimation->setSpeedMult(speed); mDirection = vec.normalisedCopy(); -} - -Ogre::Vector3 CharacterController::update(float duration) -{ Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) movement += mAnimation->runAnimation(duration); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c8e92f7a92..69d73263bd 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -66,8 +66,6 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setMovementVector(const Ogre::Vector3 &vec); - void setState(CharacterState state, bool loop); CharacterState getState() const { return mState; } From a002b253d10fd882a29ef5917ac46f0cc281a932 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 Feb 2013 16:18:17 +0100 Subject: [PATCH 0213/1483] silenced a cmake warning --- cmake/OpenMWMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index d13568a688..bb200ee570 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -64,7 +64,7 @@ macro (opencs_units_noqt dir) foreach (u ${ARGN}) add_unit (OPENCS ${dir} ${u}) endforeach (u) -endmacro (opencs_units) +endmacro (opencs_units_noqt) macro (opencs_hdrs dir) foreach (u ${ARGN}) @@ -76,4 +76,4 @@ macro (opencs_hdrs_noqt dir) foreach (u ${ARGN}) add_hdr (OPENCS ${dir} ${u}) endforeach (u) -endmacro (opencs_hdrs) +endmacro (opencs_hdrs_noqt) From 5334934612d49b065f71c78717c27c08d1e5ae2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 18:03:09 +0100 Subject: [PATCH 0214/1483] Listen to render window updates and properly activate/deactivate occlusion queries pre/post update. --- apps/openmw/mwrender/refraction.cpp | 5 +++-- apps/openmw/mwrender/renderingmanager.cpp | 19 ++++++++++++++----- apps/openmw/mwrender/renderingmanager.hpp | 8 +++++++- apps/openmw/mwrender/water.cpp | 3 ++- libs/openengine/ogre/renderer.cpp | 1 - 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 175b852238..88ad70b7f0 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -31,9 +31,9 @@ namespace MWRender Refraction::~Refraction() { + mRenderTarget->removeListener(this); Ogre::TextureManager::getSingleton().remove("WaterRefraction"); mParentCamera->getSceneManager()->destroyCamera(mCamera); - mRenderTarget->removeListener(this); } void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) @@ -56,7 +56,8 @@ namespace MWRender void Refraction::setWaterPlane(Ogre::Plane plane) { - mNearClipPlane = Ogre::Plane(-plane.normal, - (plane.d + 5) ); + /// \todo + mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,1,0), 0); } } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 18337c7d78..b2e18f1e8d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -62,6 +62,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); mRendering.setWindowEventListener(this); + mRendering.getWindow()->addListener(this); + mCompositors = new Compositors(mRendering.getViewport()); mWater = 0; @@ -174,6 +176,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const RenderingManager::~RenderingManager () { + mRendering.getWindow()->removeListener(this); mRendering.removeWindowEventListener(this); delete mPlayer; @@ -337,10 +340,6 @@ void RenderingManager::update (float duration, bool paused) mOcclusionQuery->update(duration); - // deactivate queries to make sure we aren't getting false results from several misc render targets - // (will be reactivated at the bottom of this method) - mOcclusionQuery->setActive(false); - mVideoPlayer->update (); mRendering.update(duration); @@ -396,10 +395,20 @@ void RenderingManager::update (float duration, bool paused) orig = Ogre::Vector3(orig.x, orig.z, -orig.y); mWater->update(duration, orig); } +} +void RenderingManager::preRenderTargetUpdate(const RenderTargetEvent &evt) +{ mOcclusionQuery->setActive(true); } +void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt) +{ + // deactivate queries to make sure we aren't getting false results from several misc render targets + // (will be reactivated at the bottom of this method) + mOcclusionQuery->setActive(false); +} + void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) { const MWWorld::Store &lands = @@ -886,7 +895,7 @@ void RenderingManager::applyCompositors() mCompositors->addCompositor("gbufferFinalizer", 2); mCompositors->setCompositorEnabled("gbufferFinalizer", true); */ -} + } //if (mWater) //mWater->assignTextures(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0a92bb2ea8..71ac742c2a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -11,6 +11,8 @@ #include +#include + #include "renderinginterface.hpp" #include "objects.hpp" @@ -47,7 +49,7 @@ namespace MWRender class GlobalMap; class VideoPlayer; -class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { +class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener, public Ogre::RenderTargetListener { private: @@ -137,6 +139,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void disableLights(bool sun); ///< @param sun whether or not to really disable the sunlight (otherwise just set diffuse to 0) void enableLights(bool sun); + + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + bool occlusionQuerySupported() { return mOcclusionQuery->supported(); } OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0533388bca..4ef2aea669 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -185,6 +185,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mRendering(rend), mWaterTimer(0.f), mReflection(NULL), + mRefraction(NULL), mSimulation(NULL) { mSimulation = new RippleSimulation(mSceneMgr); @@ -317,7 +318,7 @@ void Water::setHeight(const float height) { mTop = height; - mWaterPlane = Plane(Vector3::UNIT_Y, height); + mWaterPlane = Plane(Vector3::UNIT_Y, -height); if (mReflection) mReflection->setWaterPlane(mWaterPlane); diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index e6e1d46b85..039aba2264 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -211,7 +211,6 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& mRoot->initialise(false); // create a hidden 1x1 background window to keep resources when recreating the secondary (real) window - /// \todo Why does this break occlusion queries? :( /* NameValuePairList params_; params_.insert(std::make_pair("title", title)); From 979a874220267be05b290314846ce34bd054f4d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 19:01:59 +0100 Subject: [PATCH 0215/1483] Fixed the custom near clip planes --- apps/openmw/mwrender/refraction.cpp | 6 +++--- apps/openmw/mwrender/refraction.hpp | 2 +- apps/openmw/mwrender/water.cpp | 13 +++++++------ apps/openmw/mwrender/water.hpp | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 88ad70b7f0..85642bc088 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -25,6 +25,7 @@ namespace MWRender vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain); + vp->setMaterialScheme("water_reflection"); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } @@ -54,10 +55,9 @@ namespace MWRender } - void Refraction::setWaterPlane(Ogre::Plane plane) + void Refraction::setHeight(float height) { - /// \todo - mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,1,0), 0); + mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,1,0), -(height + 5)); } } diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp index 01ec86521a..e3777d9cf1 100644 --- a/apps/openmw/mwrender/refraction.hpp +++ b/apps/openmw/mwrender/refraction.hpp @@ -20,7 +20,7 @@ namespace MWRender Refraction(Ogre::Camera* parentCamera); ~Refraction(); - void setWaterPlane (Ogre::Plane plane); + void setHeight (float height); void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 4ef2aea669..877a9a953d 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -155,10 +155,10 @@ void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) mRenderActive = false; } -void PlaneReflection::setWaterPlane (Plane plane) +void PlaneReflection::setHeight (float height) { - mWaterPlane = plane; - mErrorPlane = Plane(plane.normal, mWaterPlane.d - 5); + mWaterPlane = Plane(Ogre::Vector3(0,1,0), height); + mErrorPlane = Plane(Ogre::Vector3(0,1,0), height - 5); } void PlaneReflection::setActive (bool active) @@ -321,9 +321,9 @@ void Water::setHeight(const float height) mWaterPlane = Plane(Vector3::UNIT_Y, -height); if (mReflection) - mReflection->setWaterPlane(mWaterPlane); + mReflection->setHeight(height); if (mRefraction) - mRefraction->setWaterPlane(mWaterPlane); + mRefraction->setHeight(height); mWaterNode->setPosition(0, height, 0); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); @@ -423,7 +423,7 @@ void Water::applyRTT() { mReflection = new PlaneReflection(mSceneMgr, mSky); mReflection->setParentCamera (mCamera); - mReflection->setWaterPlane(mWaterPlane); + mReflection->setHeight(mTop); mWater->setRenderQueueGroup(RQG_Water); } else @@ -434,6 +434,7 @@ void Water::applyRTT() mRefraction = NULL; mRefraction = new Refraction(mCamera); + mRefraction->setHeight(mTop); } void Water::applyVisibilityMask() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 67c788c817..cf181674a5 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -39,7 +39,7 @@ namespace MWRender { : mSceneMgr(sceneManager) {} virtual ~Reflection() {} - virtual void setWaterPlane (Ogre::Plane plane) {} + virtual void setHeight (float height) {} virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } void setUnderwater(bool underwater) { mIsUnderwater = underwater; } virtual void setActive (bool active) {} @@ -72,7 +72,7 @@ namespace MWRender { PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky); virtual ~PlaneReflection(); - virtual void setWaterPlane (Ogre::Plane plane); + virtual void setHeight (float height); virtual void setActive (bool active); virtual void setVisibilityMask (int flags); From a44dfcd2acaf65ea657a14545b718718957e4872 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 19:28:31 +0100 Subject: [PATCH 0216/1483] Now that refraction is separated out, we don't have to worry about rendering order. Should fix transparency blending issues around water (eg waterfalls) for good. --- apps/openmw/mwrender/renderingmanager.cpp | 10 +++++----- apps/openmw/mwrender/water.cpp | 5 +---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b2e18f1e8d..aa73bc49bb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -867,8 +867,8 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw) mVideoPlayer->setResolution (rw->getWidth(), rw->getHeight()); const Settings::CategorySettingVector& changed = Settings::Manager::apply(); - MWBase::Environment::get().getInputManager()->processChangedSettings(changed); //FIXME - MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); // FIXME + MWBase::Environment::get().getInputManager()->processChangedSettings(changed); + MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); } void RenderingManager::windowClosed(Ogre::RenderWindow* rw) @@ -878,9 +878,9 @@ void RenderingManager::windowClosed(Ogre::RenderWindow* rw) bool RenderingManager::waterShaderSupported() { - const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) - return false; + //const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); + //if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) + //return false; return true; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 877a9a953d..0eb35323db 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -424,11 +424,8 @@ void Water::applyRTT() mReflection = new PlaneReflection(mSceneMgr, mSky); mReflection->setParentCamera (mCamera); mReflection->setHeight(mTop); - mWater->setRenderQueueGroup(RQG_Water); } - else - mWater->setRenderQueueGroup(RQG_Alpha); - + mWater->setRenderQueueGroup(RQG_Alpha); delete mRefraction; mRefraction = NULL; From 5cc8af0f14ff975899f2bfbc4e5801311e9191db Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 20:06:03 +0100 Subject: [PATCH 0217/1483] fix map positions --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 27 +++++++++++++++------------ apps/openmw/mwrender/localmap.hpp | 8 ++++++++ apps/openmw/mwrender/water.cpp | 2 +- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 8fecf4c34b..dd5289edb1 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -150,7 +150,7 @@ namespace MWGui if (!mFirstLoad) { mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName()); - //mRectangle->setVisible(true); + mRectangle->setVisible(true); } for (unsigned int i = 0; igetNumCompositors(); ++i) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 1d338df122..3a906138b8 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -187,15 +187,6 @@ void LocalMap::render(const float x, const float y, const float zlow, const float zhigh, const float xw, const float yw, const std::string& texture) { - // disable fog (only necessary for fixed function, the shader based - // materials already do this through local_map material configuration) - const float fStart = mRendering->getScene()->getFogStart(); - const float fEnd = mRendering->getScene()->getFogEnd(); - const ColourValue& clr = mRendering->getScene()->getFogColour(); - mRendering->getScene()->setFog(FOG_NONE); - - // make everything visible - mCameraNode->setPosition(Vector3(x, zhigh+100000, y)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite @@ -224,6 +215,9 @@ void LocalMap::render(const float x, const float y, TU_RENDERTARGET); RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); + + mCameraSettings[rtt] = Vector3(x, zhigh+100000, y); + rtt->setAutoUpdated(false); Viewport* vp = rtt->addViewport(mCellCamera); vp->setOverlaysEnabled(false); @@ -266,13 +260,19 @@ void LocalMap::render(const float x, const float y, //rtt->writeContentsToFile("./" + texture + ".jpg"); } } - - // re-enable fog - mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd); } void LocalMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { + // disable fog (only necessary for fixed function, the shader based + // materials already do this through local_map material configuration) + mOldFogStart = mRendering->getScene()->getFogStart(); + mOldFogEnd = mRendering->getScene()->getFogEnd(); + mOldFogClr = mRendering->getScene()->getFogColour(); + mRendering->getScene()->setFog(FOG_NONE); + + mCellCamera->setPosition(mCameraSettings[evt.source]); + mRenderingManager->disableLights(true); mLight->setVisible(true); evt.source->setAutoUpdated(false); @@ -283,6 +283,9 @@ void LocalMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) mRenderingManager->enableLights(true); mLight->setVisible(false); evt.source->removeListener(this); + + // re-enable fog + mRendering->getScene()->setFog(FOG_LINEAR, mOldFogClr, 0, mOldFogStart, mOldFogEnd); } void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 2b1aa3f625..1f528f1386 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace MWWorld @@ -120,6 +121,13 @@ namespace MWRender int mCellX, mCellY; Ogre::AxisAlignedBox mBounds; std::string mInteriorName; + + Ogre::ColourValue mOldFogClr; + float mOldFogStart; + float mOldFogEnd; + + // maps texture name to according camera settings + std::map mCameraSettings; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0eb35323db..f2854c879a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -401,7 +401,7 @@ void Water::update(float dt, Ogre::Vector3 player) mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - //if (player.y <= mTop) + if (player.y <= mTop) { mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } From fa07288b151d8c6addd9d42177737f29f9b82d78 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 20:29:50 +0100 Subject: [PATCH 0218/1483] tweaked map light color --- apps/openmw/mwrender/localmap.cpp | 4 ++++ apps/openmw/mwrender/localmap.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 3a906138b8..ccad0a5e8f 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -271,6 +271,9 @@ void LocalMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) mOldFogClr = mRendering->getScene()->getFogColour(); mRendering->getScene()->setFog(FOG_NONE); + mOldAmbient = mRendering->getScene()->getAmbientLight(); + mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); + mCellCamera->setPosition(mCameraSettings[evt.source]); mRenderingManager->disableLights(true); @@ -286,6 +289,7 @@ void LocalMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) // re-enable fog mRendering->getScene()->setFog(FOG_LINEAR, mOldFogClr, 0, mOldFogStart, mOldFogEnd); + mRendering->getScene()->setAmbientLight(mOldAmbient); } void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 1f528f1386..afdf4b6e57 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -123,6 +123,7 @@ namespace MWRender std::string mInteriorName; Ogre::ColourValue mOldFogClr; + Ogre::ColourValue mOldAmbient; float mOldFogStart; float mOldFogEnd; From 91513206a01e5aa482d582f61179da93c9411ae1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 12:02:51 -0800 Subject: [PATCH 0219/1483] Don't use per-animation accumulation values This breaks walking diagonally and "jumping" (which technically wasn't jumping anyway). --- apps/openmw/mwmechanics/character.cpp | 70 ++++++++++++--------------- apps/openmw/mwmechanics/character.hpp | 2 - 2 files changed, 30 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f5a4dda51b..fed6e3e3ef 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -34,39 +34,37 @@ namespace MWMechanics static const struct { CharacterState state; const char groupname[32]; - Ogre::Vector3 accumulate; } sStateList[] = { - { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle2, "idle2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle3, "idle3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle4, "idle4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle5, "idle5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle6, "idle6", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle7, "idle7", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle8, "idle8", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle9, "idle9", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle, "idle" }, + { CharState_Idle2, "idle2" }, + { CharState_Idle3, "idle3" }, + { CharState_Idle4, "idle4" }, + { CharState_Idle5, "idle5" }, + { CharState_Idle6, "idle6" }, + { CharState_Idle7, "idle7" }, + { CharState_Idle8, "idle8" }, + { CharState_Idle9, "idle9" }, - { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, - { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, - { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, - { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, + { CharState_WalkForward, "walkforward" }, + { CharState_WalkBack, "walkback" }, + { CharState_WalkLeft, "walkleft" }, + { CharState_WalkRight, "walkright" }, - { CharState_Death1, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death2, "death2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death3, "death3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death4, "death4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death5, "death5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death1, "death1" }, + { CharState_Death2, "death2" }, + { CharState_Death3, "death3" }, + { CharState_Death4, "death4" }, + { CharState_Death5, "death5" }, }; static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); -static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 *accum) +static void getStateInfo(CharacterState state, std::string *group) { for(size_t i = 0;i < sStateListSize;i++) { if(sStateList[i].state == state) { *group = sStateList[i].groupname; - *accum = sStateList[i].accumulate; return; } } @@ -75,24 +73,25 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) + : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { if(!mAnimation) return; mAnimation->setController(this); - Ogre::Vector3 accum; - getStateInfo(mState, &mCurrentGroup, &accum); - mAnimation->setAccumulation(accum); + getStateInfo(mState, &mCurrentGroup); + /* Accumulate along X/Y only for now, until we can figure out how we should + * handle knockout and death which moves the character down. */ + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) - , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) + , mSkipAnim(rhs.mSkipAnim) { if(!mAnimation) return; @@ -144,9 +143,6 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - // HACK: The length we get is too large. - float speed = std::max(1.0f, vec.length() / 32.0f); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) @@ -164,20 +160,17 @@ Ogre::Vector3 CharacterController::update(float duration) setState(CharState_Idle, true); } + // FIXME: The speed should actually be determined by the character's stance + // (running, sneaking, etc) and stats, rather than the length of the vector. + float speed = std::max(1.0f, vec.length() / 32.0f); if(mAnimation) mAnimation->setSpeedMult(speed); - mDirection = vec.normalisedCopy(); Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_Idle || getState() >= CharState_Death1)) - { - movement = mDirection * movement.length(); - } - return movement; } @@ -196,7 +189,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_Idle; - mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) @@ -225,12 +217,10 @@ void CharacterController::setState(CharacterState state, bool loop) mAnimQueue.clear(); std::string anim; - Ogre::Vector3 accum; - getStateInfo(mState, &anim, &accum); + getStateInfo(mState, &anim); if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->setAccumulation(accum); mAnimation->play(mCurrentGroup, "start", loop); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 69d73263bd..c5f29beef8 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,8 +45,6 @@ class CharacterController typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; - Ogre::Vector3 mDirection; - std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; From 4c973a0f6767570a4ed07d0265fe949e7f0f7beb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Feb 2013 13:46:54 +0100 Subject: [PATCH 0220/1483] constructing documents from a file list instead of a single name --- apps/opencs/editor.cpp | 12 +++++-- apps/opencs/model/doc/document.cpp | 42 +++++++++++++++++++++-- apps/opencs/model/doc/document.hpp | 10 ++++-- apps/opencs/model/doc/documentmanager.cpp | 5 +-- apps/opencs/model/doc/documentmanager.hpp | 7 +++- 5 files changed, 66 insertions(+), 10 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 2340c71ee2..57e31e19ea 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -22,13 +22,16 @@ void CS::Editor::createDocument() mStartup.hide(); /// \todo open the ESX picker instead - /// \todo remove the following code for creating initial records into the document manager + /// \todo move the following code for creating initial records into the document manager std::ostringstream stream; stream << "NewDocument" << (++mNewDocumentIndex); - CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); + std::vector files; + files.push_back (stream.str()); + + CSMDoc::Document *document = mDocumentManager.addDocument (files, true); static const char *sGlobals[] = { @@ -60,7 +63,10 @@ void CS::Editor::loadDocument() stream << "Document" << (++mNewDocumentIndex); - CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); + std::vector files; + files.push_back (stream.str()); + + CSMDoc::Document *document = mDocumentManager.addDocument (files, false); static const char *sGlobals[] = { diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 9d26944832..93d664314e 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,10 +1,48 @@ #include "document.hpp" -CSMDoc::Document::Document (const std::string& name) +#include + +void CSMDoc::Document::load (const std::vector::const_iterator& begin, + const std::vector::const_iterator& end) +{ + for (std::vector::const_iterator iter (begin); iter!=end; ++iter) + std::cout << "pretending to load " << iter->string() << std::endl; + + /// \todo load content files +} + +void CSMDoc::Document::createBase() +{ + std::cout << "pretending to create base file records" << std::endl; + + /// \todo create mandatory records for base content file +} + +CSMDoc::Document::Document (const std::vector& files, bool new_) : mTools (mData) { - mName = name; ///< \todo replace with ESX list + if (files.empty()) + throw std::runtime_error ("Empty content file sequence"); + + /// \todo adjust last file name: + /// \li make sure it is located in the data-local directory (adjust path if necessary) + /// \li make sure the extension matches the new scheme (change it if necesarry) + + mName = files.back().filename().string(); + + if (files.size()>1 || !new_) + { + std::vector::const_iterator end = files.end(); + + if (new_) + --end; + + load (files.begin(), end); + } + + if (new_ && files.size()==1) + createBase(); connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 43e8bba37b..28cc19d449 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -3,6 +3,8 @@ #include +#include + #include #include #include @@ -38,10 +40,14 @@ namespace CSMDoc Document (const Document&); Document& operator= (const Document&); + void load (const std::vector::const_iterator& begin, + const std::vector::const_iterator& end); + + void createBase(); + public: - Document (const std::string& name); - ///< \todo replace name with ESX list + Document (const std::vector& files, bool new_); QUndoStack& getUndoStack(); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 8ae2764f24..740c0b5827 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -14,9 +14,10 @@ CSMDoc::DocumentManager::~DocumentManager() delete *iter; } -CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::string& name) +CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector& files, + bool new_) { - Document *document = new Document (name); + Document *document = new Document (files, new_); mDocuments.push_back (document); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 730c7fae1d..a307b76a57 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace CSMDoc { class Document; @@ -21,8 +23,11 @@ namespace CSMDoc ~DocumentManager(); - Document *addDocument (const std::string& name); + Document *addDocument (const std::vector& files, bool new_); ///< The ownership of the returned document is not transferred to the caller. + /// + /// \param new_ Do not load the last content file in \a files and instead create in an + /// appropriate way. bool removeDocument (Document *document); ///< \return last document removed? From ba0d13fc12f2be6b483a09025b329f97974ae9b4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Feb 2013 13:50:38 +0100 Subject: [PATCH 0221/1483] moved code for creating new base content records into the Document class --- apps/opencs/editor.cpp | 19 +------------------ apps/opencs/model/doc/document.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 57e31e19ea..7156db94e7 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -22,7 +22,6 @@ void CS::Editor::createDocument() mStartup.hide(); /// \todo open the ESX picker instead - /// \todo move the following code for creating initial records into the document manager std::ostringstream stream; @@ -33,22 +32,6 @@ void CS::Editor::createDocument() CSMDoc::Document *document = mDocumentManager.addDocument (files, true); - static const char *sGlobals[] = - { - "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 - }; - - for (int i=0; sGlobals[i]; ++i) - { - ESM::Global record; - record.mId = sGlobals[i]; - record.mValue = i==0 ? 1 : 0; - record.mType = ESM::VT_Float; - document->getData().getGlobals().add (record); - } - - document->getData().merge(); /// \todo remove once proper ESX loading is implemented - mViewManager.addView (document); } @@ -57,7 +40,7 @@ void CS::Editor::loadDocument() mStartup.hide(); /// \todo open the ESX picker instead - /// \todo replace the manual record creation and load the ESX files instead + /// \todo remove the manual record creation and load the ESX files instead std::ostringstream stream; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 93d664314e..14e34d0baf 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -14,9 +14,19 @@ void CSMDoc::Document::load (const std::vector::const_i void CSMDoc::Document::createBase() { - std::cout << "pretending to create base file records" << std::endl; + static const char *sGlobals[] = + { + "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + }; - /// \todo create mandatory records for base content file + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global record; + record.mId = sGlobals[i]; + record.mValue = i==0 ? 1 : 0; + record.mType = ESM::VT_Float; + getData().getGlobals().add (record); + } } CSMDoc::Document::Document (const std::vector& files, bool new_) From 1747c1e01ac4729a37b328a89972c9143ab05e96 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 07:10:14 -0800 Subject: [PATCH 0222/1483] Integrate a new movement solver to handle object movement and collisions Temporary, and pretty breoken. Needs some serious integration fixes. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 7 + apps/openmw/mwmechanics/character.cpp | 32 ++++- apps/openmw/mwmechanics/character.hpp | 5 + apps/openmw/mwmechanics/movementsolver.cpp | 154 +++++++++++++++++++++ apps/openmw/mwmechanics/movementsolver.hpp | 37 +++++ apps/openmw/mwworld/worldimp.hpp | 4 + 7 files changed, 233 insertions(+), 8 deletions(-) create mode 100644 apps/openmw/mwmechanics/movementsolver.cpp create mode 100644 apps/openmw/mwmechanics/movementsolver.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 73baa4e72e..5f425f7a03 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate + aiescort aiactivate movementsolver ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a426e34543..5f6e27867d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -20,6 +20,11 @@ namespace OEngine { class Fader; } + + namespace Physic + { + class PhysicEngine; + } } namespace ESM @@ -300,6 +305,8 @@ namespace MWBase /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const = 0; /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index fed6e3e3ef..7962e197ee 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -25,9 +25,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" +#include "movementsolver.hpp" + + namespace MWMechanics { @@ -75,6 +79,7 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { + mMovementSolver = new MovementSolver(mPtr); if(!mAnimation) return; @@ -93,12 +98,18 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { + mMovementSolver = new MovementSolver(mPtr); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); } +CharacterController::~CharacterController() +{ + delete mMovementSolver; +} + void CharacterController::markerEvent(float time, const std::string &evt) { @@ -160,18 +171,25 @@ Ogre::Vector3 CharacterController::update(float duration) setState(CharState_Idle, true); } - // FIXME: The speed should actually be determined by the character's stance - // (running, sneaking, etc) and stats, rather than the length of the vector. - float speed = std::max(1.0f, vec.length() / 32.0f); - if(mAnimation) - mAnimation->setSpeedMult(speed); - Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) + { + // FIXME: The speed should actually be determined by the character's + // stance (running, sneaking, etc) and stats + mAnimation->setSpeedMult(1.0f); movement += mAnimation->runAnimation(duration); + } mSkipAnim = false; - return movement; + if(duration > 0.0f) + { + Ogre::Vector3 pos(mPtr.getCellRef().mPos.pos); + // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? + Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); + MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); + } + + return Ogre::Vector3(0.0f); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c5f29beef8..efd90ca196 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -13,6 +13,8 @@ namespace MWRender namespace MWMechanics { +class MovementSolver; + enum CharacterState { CharState_Idle, CharState_Idle2, @@ -49,6 +51,8 @@ class CharacterController CharacterState mState; bool mSkipAnim; + MovementSolver *mMovementSolver; + protected: /* Called by the animation whenever a new text key is reached. */ void markerEvent(float time, const std::string &evt); @@ -58,6 +62,7 @@ protected: public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); + virtual ~CharacterController(); Ogre::Vector3 update(float duration); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp new file mode 100644 index 0000000000..219f077e4a --- /dev/null +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -0,0 +1,154 @@ +#include "movementsolver.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) + : mPtr(ptr) + , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) +{ +} + +MovementSolver::~MovementSolver() +{ + // nothing to do +} + +void MovementSolver::clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) +{ + //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. + //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. + float backoff; + + backoff = in.dotProduct(normal); + if(backoff < 0.0f) + backoff *= overbounce; + else + backoff /= overbounce; + + out = in - (normal*backoff); +} + +void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) +{ + Ogre::Vector3 normalizedDirection(direction); + normalizedDirection.normalise(); + + // no divide by normalizedDirection.length necessary because it's normalized + velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); +} + +bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) +{ + static const float maxslope = 45.0f; + traceResults trace; // no initialization needed + + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), + position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + halfExtents, verticalRotation, isInterior, mEngine); + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > maxslope)) + return false; + + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); + if(getSlope(trace.planenormal) < maxslope) + { + // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. + position = trace.endpos; + return true; + } + + return false; +} + +float MovementSolver::getSlope(const Ogre::Vector3 &normal) +{ + return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); +} + + +Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +{ + mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + + /* Anything to collide with? */ + if(1 || !mPhysicActor || !mPhysicActor->getCollisionMode()) + return position+movement; + + traceResults trace; //no initialization needed + int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + float maxslope=45; + + Ogre::Vector3 horizontalVelocity = movement/time; + Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); + + float remainingTime = time; + bool isInterior = !mPtr.getCell()->isExterior(); + float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); + + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); + if(trace.fraction < 1.0f) + { + if(getSlope(trace.planenormal) > maxslope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } + } + + do { + // trace to where character would go if there were no obstructions + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); + newPosition = trace.endpos; + currentNormal = trace.planenormal; + remainingTime = remainingTime * (1.0f-trace.fraction); + + // check for obstructions + if(trace.fraction != 1.0f) + { + //std::cout<<"angle: "< maxslope || currentNormal == lastNormal) + { + if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) + std::cout<< "stepped" < + +namespace MWMechanics +{ + class MovementSolver + { + public: + MovementSolver(const MWWorld::Ptr &ptr); + virtual ~MovementSolver(); + + Ogre::Vector3 move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + + private: + bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); + + void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce); + void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction); + + float getSlope(const Ogre::Vector3 &normal); + + MWWorld::Ptr mPtr; + OEngine::Physic::PhysicEngine *mEngine; + OEngine::Physic::PhysicActor *mPhysicActor; + + float verticalVelocity; + }; +} + +#endif /* GAME_MWMECHANICS_MOVEMENTSOLVER_H */ diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4899a88070..062387e922 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -347,6 +347,10 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const + { return mPhysEngine; } + /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); From bf037b7d299c4ca0ebb4c50e9e656056f7f030e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Feb 2013 18:03:03 +0100 Subject: [PATCH 0223/1483] Removed problematic ModVertexAlpha method, now done in shader --- apps/openmw/mwrender/sky.cpp | 45 ---------------------------- apps/openmw/mwrender/sky.hpp | 2 -- extern/shiny/CMakeLists.txt | 7 ----- extern/shiny/Main/ShaderInstance.cpp | 20 ++++++------- files/materials/atmosphere.shader | 9 +++--- files/materials/clouds.shader | 9 +++--- 6 files changed, 18 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 60ecd43034..f8499d1e55 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -203,48 +203,6 @@ unsigned int Moon::getPhaseInt() const return 0; } -void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) -{ - // Get the vertex colour buffer of this mesh - const Ogre::VertexElement* ves_diffuse = ent->getMesh()->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE ); - HardwareVertexBufferSharedPtr colourBuffer = ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource()); - - // Lock - void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL); - - // Iterate over all vertices - int vertex_size = colourBuffer->getVertexSize(); - float * currentVertex = NULL; - for (unsigned int i=0; igetNumVertices(); ++i) - { - // Get a pointer to the vertex colour - ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex ); - - unsigned char alpha=0; - if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row - else if (meshType == 1) - { - if (i>= 49 && i <= 64) alpha = 0; // bottom-most row - else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row - else alpha = 255; - } - // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 - uint8 tmpR = static_cast(255); - uint8 tmpG = static_cast(255); - uint8 tmpB = static_cast(255); - uint8 tmpA = static_cast(alpha); - - // Modify - *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); - - // Move to the next vertex - pData = static_cast (pData) + vertex_size; - } - - // Unlock - ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock(); -} - SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : mHour(0.0f) , mDay(0) @@ -357,7 +315,6 @@ void SkyManager::create() atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); - ModVertexAlpha(atmosphere_ent, 0); } @@ -371,8 +328,6 @@ void SkyManager::create() clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); clouds_ent->setCastShadows(false); - - ModVertexAlpha(clouds_ent, 1); } mCreated = true; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index ee13608531..52fd7b4aa8 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -218,8 +218,6 @@ namespace MWRender float mGlare; // target float mGlareFade; // actual - void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType); - bool mEnabled; bool mSunEnabled; bool mMasserEnabled; diff --git a/extern/shiny/CMakeLists.txt b/extern/shiny/CMakeLists.txt index 603336413e..6eadcc1676 100644 --- a/extern/shiny/CMakeLists.txt +++ b/extern/shiny/CMakeLists.txt @@ -24,13 +24,6 @@ set(SOURCE_FILES Main/ShaderSet.cpp ) -# In Debug mode, write the shader sources to the current directory -if (DEFINED CMAKE_BUILD_TYPE) - if (CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions(-DSHINY_WRITE_SHADER_DEBUG) - endif() -endif() - if (DEFINED SHINY_USE_WAVE_SYSTEM_INSTALL) # use system install else() diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp index 07ef8dfe28..0e074c7b4b 100644 --- a/extern/shiny/Main/ShaderInstance.cpp +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -363,12 +363,12 @@ namespace sh if (Factory::getInstance ().getShaderDebugOutputEnabled ()) writeDebugFile(source, name + ".pre"); - else - { - #ifdef SHINY_WRITE_SHADER_DEBUG - writeDebugFile(source, name + ".pre"); - #endif - } + else + { + #ifdef SHINY_WRITE_SHADER_DEBUG + writeDebugFile(source, name + ".pre"); + #endif + } // why do we need our own preprocessor? there are several custom commands available in the shader files // (for example for binding uniforms to properties or auto constants) - more below. it is important that these @@ -648,12 +648,12 @@ namespace sh if (Factory::getInstance ().getShaderDebugOutputEnabled ()) writeDebugFile(source, name); - else - { + else + { #ifdef SHINY_WRITE_SHADER_DEBUG - writeDebugFile(source, name); + writeDebugFile(source, name); #endif - } + } if (!mProgram->getSupported()) { diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 295fa93768..16edc78c56 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -7,19 +7,18 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - shColourInput(float4) - shOutput(float4, colourPassthrough) + shOutput(float, alphaFade) SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); - colourPassthrough = colour; + alphaFade = shInputPosition.z < 150.0 ? 0.0 : 1.0; } #else SH_BEGIN_PROGRAM - shInput(float4, colourPassthrough) + shInput(float, alphaFade) #if MRT shDeclareMrtOutput(1) #endif @@ -27,7 +26,7 @@ SH_START_PROGRAM { - shOutputColour(0) = colourPassthrough * atmosphereColour; + shOutputColour(0) = atmosphereColour * float4(1,1,1,alphaFade); #if MRT shOutputColour(1) = float4(1,1,1,1); diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index f4258bf5d4..9126ae423a 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -8,21 +8,20 @@ shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) shVertexInput(float2, uv0) shOutput(float2, UV) - shColourInput(float4) - shOutput(float4, colourPassthrough) + shOutput(float, alphaFade) SH_START_PROGRAM { - colourPassthrough = colour; shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; + alphaFade = shInputPosition.z < 100.f ? 0 : 1; } #else SH_BEGIN_PROGRAM shInput(float2, UV) - shInput(float4, colourPassthrough) + shInput(float, alphaFade) #if MRT shDeclareMrtOutput(1) #endif @@ -42,7 +41,7 @@ float4 albedo = shSample(diffuseMap1, scrolledUV) * (1-cloudBlendFactor) + shSample(diffuseMap2, scrolledUV) * cloudBlendFactor; - shOutputColour(0) = colourPassthrough * float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity); + shOutputColour(0) = float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity * alphaFade); #if MRT shOutputColour(1) = float4(1,1,1,1); From a7d910614f516092cccc0ada7625de2e451e1902 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Feb 2013 18:04:09 +0100 Subject: [PATCH 0224/1483] extern/shiny update: made caching more robust --- extern/shiny/Main/Factory.cpp | 43 ++++++++++++++++++++++++---- extern/shiny/Main/Factory.hpp | 1 + extern/shiny/Main/ShaderInstance.cpp | 15 +--------- extern/shiny/Main/ShaderSet.cpp | 1 - extern/shiny/Main/ShaderSet.hpp | 7 ----- 5 files changed, 40 insertions(+), 27 deletions(-) diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 82d6648110..c63a9e367a 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -191,15 +191,48 @@ namespace sh &mGlobalSettings); int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceFile)); + mShadersLastModifiedNew[sourceFile] = lastModified; if (mShadersLastModified.find(sourceFile) != mShadersLastModified.end() && mShadersLastModified[sourceFile] != lastModified) { - newSet.markDirty (); + // delete any outdated shaders based on this shader set. + if ( boost::filesystem::exists(mPlatform->getCacheFolder()) + && boost::filesystem::is_directory(mPlatform->getCacheFolder())) + { + boost::filesystem::directory_iterator end_iter; + for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter) + { + if (boost::filesystem::is_regular_file(dir_iter->status()) ) + { + boost::filesystem::path file = dir_iter->path(); + + std::string pathname = file.filename().string(); + + // get first part of filename, e.g. main_fragment_546457654 -> main_fragment + // there is probably a better method for this... + std::vector tokens; + boost::split(tokens, pathname, boost::is_any_of("_")); + tokens.erase(--tokens.end()); + std::string shaderName; + for (std::vector::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();) + { + shaderName += *(vector_iter++); + if (vector_iter != tokens.end()) + shaderName += "_"; + } + + if (shaderName == it->first) + { + boost::filesystem::remove(file); + std::cout << "Removing outdated file: " << file << std::endl; + } + } + } + } + anyShaderDirty = true; } - mShadersLastModified[sourceFile] = lastModified; - mShaderSets.insert(std::make_pair(it->first, newSet)); } } @@ -313,11 +346,11 @@ namespace sh if (mReadSourceCache) { - // save the last modified time of shader sources + // save the last modified time of shader sources (as of when they were loaded) std::ofstream file; file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); - for (LastModifiedMap::const_iterator it = mShadersLastModified.begin(); it != mShadersLastModified.end(); ++it) + for (LastModifiedMap::const_iterator it = mShadersLastModifiedNew.begin(); it != mShadersLastModifiedNew.end(); ++it) { file << it->first << "\n" << it->second << std::endl; } diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp index 799dd71eb0..1062c079c9 100644 --- a/extern/shiny/Main/Factory.hpp +++ b/extern/shiny/Main/Factory.hpp @@ -185,6 +185,7 @@ namespace sh ConfigurationMap mConfigurations; LodConfigurationMap mLodConfigurations; LastModifiedMap mShadersLastModified; + LastModifiedMap mShadersLastModifiedNew; PropertySetGet mGlobalSettings; diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp index 0e074c7b4b..1539128aba 100644 --- a/extern/shiny/Main/ShaderInstance.cpp +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -337,8 +337,7 @@ namespace sh size_t pos; bool readCache = Factory::getInstance ().getReadSourceCache () && boost::filesystem::exists( - Factory::getInstance ().getCacheFolder () + "/" + mName) - && !mParent->isDirty (); + Factory::getInstance ().getCacheFolder () + "/" + mName); bool writeCache = Factory::getInstance ().getWriteSourceCache (); @@ -363,12 +362,6 @@ namespace sh if (Factory::getInstance ().getShaderDebugOutputEnabled ()) writeDebugFile(source, name + ".pre"); - else - { - #ifdef SHINY_WRITE_SHADER_DEBUG - writeDebugFile(source, name + ".pre"); - #endif - } // why do we need our own preprocessor? there are several custom commands available in the shader files // (for example for binding uniforms to properties or auto constants) - more below. it is important that these @@ -648,12 +641,6 @@ namespace sh if (Factory::getInstance ().getShaderDebugOutputEnabled ()) writeDebugFile(source, name); - else - { -#ifdef SHINY_WRITE_SHADER_DEBUG - writeDebugFile(source, name); -#endif - } if (!mProgram->getSupported()) { diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp index 2702ece194..413d7d1a26 100644 --- a/extern/shiny/Main/ShaderSet.cpp +++ b/extern/shiny/Main/ShaderSet.cpp @@ -17,7 +17,6 @@ namespace sh , mName(name) , mCgProfile(cgProfile) , mHlslProfile(hlslProfile) - , mIsDirty(false) { if (type == "vertex") mType = GPT_Vertex; diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp index 776750598a..a423b6779f 100644 --- a/extern/shiny/Main/ShaderSet.hpp +++ b/extern/shiny/Main/ShaderSet.hpp @@ -30,9 +30,6 @@ namespace sh /// so it does not matter if you pass any extra properties that the shader does not care about. ShaderInstance* getInstance (PropertySetGet* properties); - void markDirty() { mIsDirty = true; } - ///< Signals that the cache is out of date, and thus should not be used this time - private: PropertySetGet* getCurrentGlobalSettings() const; std::string getBasePath() const; @@ -41,12 +38,8 @@ namespace sh std::string getHlslProfile() const; int getType() const; - bool isDirty() { return mIsDirty; } - friend class ShaderInstance; - bool mIsDirty; - private: GpuProgramType mType; std::string mSource; From bec538bfa155717b04287aed98c4e6b86b99a73c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 09:19:59 -0800 Subject: [PATCH 0225/1483] Always declare operator<< for using a TextKeyMap with Ogre::Any --- components/nifogre/ogre_nif_loader.cpp | 3 --- components/nifogre/ogre_nif_loader.hpp | 10 ++++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8175279d05..b878c29f40 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -54,9 +54,6 @@ typedef unsigned char ubyte; namespace std { -// These operators allow extra data types to be stored in an Ogre::Any -// object, which can then be stored in user object bindings on the nodes - // TODO: Do something useful ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) { return o; } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 13a76d4721..12be522332 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -81,4 +81,14 @@ public: } +namespace std +{ + +// These operators allow extra data types to be stored in an Ogre::Any +// object, which can then be stored in user object bindings on the nodes + +ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&); + +} + #endif From 6b32fa7999b3bd6f0341cef088b616b547395907 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 09:48:21 -0800 Subject: [PATCH 0226/1483] Use the correct position for the actor --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7962e197ee..29ea723ed8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -183,7 +183,7 @@ Ogre::Vector3 CharacterController::update(float duration) if(duration > 0.0f) { - Ogre::Vector3 pos(mPtr.getCellRef().mPos.pos); + Ogre::Vector3 pos(mPtr.getRefData().getPosition().pos); // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); From e94976592256a70d76218753992b77a02eeecd99 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Feb 2013 19:21:47 +0100 Subject: [PATCH 0227/1483] cloud blending now as before (0 -> 0.25 -> 1) --- files/materials/clouds.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index 9126ae423a..4b1868fb40 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -14,7 +14,7 @@ { shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; - alphaFade = shInputPosition.z < 100.f ? 0 : 1; + alphaFade = (shInputPosition.z <= 200.f) ? ((shInputPosition.z <= 100.f) ? 0.0 : 0.25) : 1.0; } #else From 1a5cb8760d6047ee57cb2b4333248ece3cad9d09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 11:04:20 -0800 Subject: [PATCH 0228/1483] Rotate movement vector to world space before passing to the movement solver --- apps/openmw/mwmechanics/character.cpp | 11 ++++++++++- apps/openmw/mwmechanics/movementsolver.cpp | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 29ea723ed8..8eb0caf58a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -183,7 +183,16 @@ Ogre::Vector3 CharacterController::update(float duration) if(duration > 0.0f) { - Ogre::Vector3 pos(mPtr.getRefData().getPosition().pos); + const ESM::Position &refpos = mPtr.getRefData().getPosition(); + + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; + + Ogre::Vector3 pos(refpos.pos); + // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 219f077e4a..a758c76f34 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -9,6 +9,7 @@ namespace MWMechanics MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) : mPtr(ptr) , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) + , verticalVelocity(0.0f) { } @@ -71,11 +72,10 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) { - mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); - /* Anything to collide with? */ - if(1 || !mPhysicActor || !mPhysicActor->getCollisionMode()) - return position+movement; + mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + if(!mPhysicActor || !mPhysicActor->getCollisionMode()) + return position + movement; traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. From 39cf7b0b42f32e98e9cb2864eb7361d30a4ad979 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 11:17:48 -0800 Subject: [PATCH 0229/1483] Pass the Ptr of the object being moved to the move method This prevents having to store another copy of it, which risks getting out of sync. --- apps/openmw/mwmechanics/character.cpp | 8 +++----- apps/openmw/mwmechanics/movementsolver.cpp | 20 ++++++++++++++------ apps/openmw/mwmechanics/movementsolver.hpp | 22 +++++++++++++++------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8eb0caf58a..b98a863ae2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -79,7 +79,7 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { - mMovementSolver = new MovementSolver(mPtr); + mMovementSolver = new MovementSolver(); if(!mAnimation) return; @@ -98,7 +98,7 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { - mMovementSolver = new MovementSolver(mPtr); + mMovementSolver = new MovementSolver(); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ @@ -191,10 +191,8 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * movement; - Ogre::Vector3 pos(refpos.pos); - // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? - Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); + Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); } diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index a758c76f34..4a7a59cb31 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -1,14 +1,20 @@ #include "movementsolver.hpp" +#include "libs/openengine/bullet/trace.h" +#include "libs/openengine/bullet/physic.hpp" + +#include "../mwworld/ptr.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include + + namespace MWMechanics { -MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) - : mPtr(ptr) - , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) +MovementSolver::MovementSolver() + : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) , verticalVelocity(0.0f) { } @@ -70,10 +76,12 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) } -Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) { + Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + /* Anything to collide with? */ - mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + mPhysicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); if(!mPhysicActor || !mPhysicActor->getCollisionMode()) return position + movement; @@ -86,7 +94,7 @@ Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Ve Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); float remainingTime = time; - bool isInterior = !mPtr.getCell()->isExterior(); + bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 lastNormal(0.0f); diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 8bd05fa15e..450bc055ed 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -1,22 +1,31 @@ #ifndef GAME_MWMECHANICS_MOVEMENTSOLVER_H #define GAME_MWMECHANICS_MOVEMENTSOLVER_H -#include "libs/openengine/bullet/trace.h" -#include "libs/openengine/bullet/physic.hpp" +#include -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; +} -#include +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + class PhysicActor; + } +} namespace MWMechanics { class MovementSolver { public: - MovementSolver(const MWWorld::Ptr &ptr); + MovementSolver(); virtual ~MovementSolver(); - Ogre::Vector3 move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); private: bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); @@ -26,7 +35,6 @@ namespace MWMechanics float getSlope(const Ogre::Vector3 &normal); - MWWorld::Ptr mPtr; OEngine::Physic::PhysicEngine *mEngine; OEngine::Physic::PhysicActor *mPhysicActor; From ee9b19d2ed92c1d9bdb03f9216d398cb42b1fb03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 12:04:06 -0800 Subject: [PATCH 0230/1483] Make sure to remove a Ptr from the activators when requested --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9e76084f5a..085cb66534 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -188,6 +188,7 @@ namespace MWMechanics if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); + mActivators.removeActivator(ptr); } void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) From 2f8affc95507e5f7264a91da06e5ff440e9b0c21 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 12:58:06 -0800 Subject: [PATCH 0231/1483] Make sure the player's controller is properly updated when they change --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 085cb66534..eee72f8805 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -309,6 +309,12 @@ namespace MWMechanics } winMgr->configureSkills (majorSkills, minorSkills); + + // HACK? The player has been changed, so a new Animation object may + // have been made for them. Make sure they're properly updated. + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + mActors.removeActor(ptr); + mActors.addActor(ptr); } mActors.update(duration, paused); From 66ec4ca7d9e8cd9abaea4dbee0a3b345ae66cabb Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Mon, 4 Feb 2013 22:14:14 +0100 Subject: [PATCH 0232/1483] Split launcher specific code from DataFilesList back to DataFilesPage. --- apps/launcher/CMakeLists.txt | 9 + apps/launcher/datafilespage.cpp | 533 +++++++++++++++++ apps/launcher/datafilespage.hpp | 80 +++ apps/launcher/maindialog.cpp | 21 +- apps/launcher/maindialog.hpp | 4 +- .../launcher}/utils/profilescombobox.cpp | 0 .../launcher}/utils/profilescombobox.hpp | 0 .../launcher}/utils/textinputdialog.cpp | 0 .../launcher}/utils/textinputdialog.hpp | 0 apps/opencs/view/doc/opendialog.cpp | 39 +- components/CMakeLists.txt | 2 +- components/fileorderlist/datafileslist.cpp | 563 +----------------- components/fileorderlist/datafileslist.hpp | 31 +- 13 files changed, 706 insertions(+), 576 deletions(-) create mode 100644 apps/launcher/datafilespage.cpp create mode 100644 apps/launcher/datafilespage.hpp rename {components/fileorderlist => apps/launcher}/utils/profilescombobox.cpp (100%) rename {components/fileorderlist => apps/launcher}/utils/profilescombobox.hpp (100%) rename {components/fileorderlist => apps/launcher}/utils/textinputdialog.cpp (100%) rename {components/fileorderlist => apps/launcher}/utils/textinputdialog.hpp (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 73efb9ee51..ce0649cd64 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -3,6 +3,9 @@ set(LAUNCHER main.cpp maindialog.cpp playpage.cpp + datafilespage.cpp + utils/profilescombobox.cpp + utils/textinputdialog.cpp launcher.rc ) @@ -11,6 +14,9 @@ set(LAUNCHER_HEADER graphicspage.hpp maindialog.hpp playpage.hpp + datafilespage.hpp + utils/profilescombobox.hpp + utils/textinputdialog.hpp ) # Headers that must be pre-processed @@ -18,6 +24,9 @@ set(LAUNCHER_HEADER_MOC graphicspage.hpp maindialog.hpp playpage.hpp + datafilespage.hpp + utils/profilescombobox.hpp + utils/textinputdialog.hpp ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp new file mode 100644 index 0000000000..52b8c9cbeb --- /dev/null +++ b/apps/launcher/datafilespage.cpp @@ -0,0 +1,533 @@ +#include + +#include +#include +#include +#include +#include +#include + +////#include "model/datafilesmodel.hpp" +////#include "model/esm/esmfile.hpp" + +#include "utils/profilescombobox.hpp" +////#include "utils/filedialog.hpp" +////#include "utils/naturalsort.hpp" +#include "utils/textinputdialog.hpp" + +#include "datafilespage.hpp" + +#include +/** + * Workaround for problems with whitespaces in paths in older versions of Boost library + */ +#if (BOOST_VERSION <= 104600) +namespace boost +{ + + template<> + inline boost::filesystem::path lexical_cast(const std::string& arg) + { + return boost::filesystem::path(arg); + } + +} /* namespace boost */ +#endif /* (BOOST_VERSION <= 104600) */ + +using namespace ESM; +using namespace std; + +DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) + : QWidget(parent) + , mCfgMgr(cfg) +{ + mDataFilesList = new DataFilesList(mCfgMgr, this); + + // Bottom part with profile options + QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); + + mProfilesComboBox = new ProfilesComboBox(this); + mProfilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + mProfilesComboBox->setInsertPolicy(QComboBox::NoInsert); + mProfilesComboBox->setDuplicatesEnabled(false); + mProfilesComboBox->setEditEnabled(false); + + mProfileToolBar = new QToolBar(this); + mProfileToolBar->setMovable(false); + mProfileToolBar->setIconSize(QSize(16, 16)); + + mProfileToolBar->addWidget(profileLabel); + mProfileToolBar->addWidget(mProfilesComboBox); + + QVBoxLayout *pageLayout = new QVBoxLayout(this); + + pageLayout->addWidget(mDataFilesList); + pageLayout->addWidget(mProfileToolBar); + + // Create a dialog for the new profile name input + mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + + connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); + + connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); + connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); + + createActions(); + setupConfig(); +} + +void DataFilesPage::createActions() +{ + // Refresh the plugins + QAction *refreshAction = new QAction(tr("Refresh"), this); + refreshAction->setShortcut(QKeySequence(tr("F5"))); + connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); + + // Profile actions + mNewProfileAction = new QAction(QIcon::fromTheme("document-new"), tr("&New Profile"), this); + mNewProfileAction->setToolTip(tr("New Profile")); + mNewProfileAction->setShortcut(QKeySequence(tr("Ctrl+N"))); + connect(mNewProfileAction, SIGNAL(triggered()), this, SLOT(newProfile())); + + mDeleteProfileAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete Profile"), this); + mDeleteProfileAction->setToolTip(tr("Delete Profile")); + mDeleteProfileAction->setShortcut(QKeySequence(tr("Delete"))); + connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); + + // Add the newly created actions to the toolbar + mProfileToolBar->addSeparator(); + mProfileToolBar->addAction(mNewProfileAction); + mProfileToolBar->addAction(mDeleteProfileAction); +} + +void DataFilesPage::setupConfig() +{ + // Open our config file + QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); + mLauncherConfig = new QSettings(config, QSettings::IniFormat); + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + QStringList profiles = mLauncherConfig->childGroups(); + + // Add the profiles to the combobox + foreach (const QString &profile, profiles) { + + if (profile.contains(QRegExp("[^a-zA-Z0-9_]"))) + continue; // Profile name contains garbage + + + qDebug() << "adding " << profile; + mProfilesComboBox->addItem(profile); + } + + // Add a default profile + if (mProfilesComboBox->findText(QString("Default")) == -1) { + mProfilesComboBox->addItem(QString("Default")); + } + + QString currentProfile = mLauncherConfig->value("CurrentProfile").toString(); + + if (currentProfile.isEmpty()) { + // No current profile selected + currentProfile = "Default"; + } + + const int currentIndex = mProfilesComboBox->findText(currentProfile); + if (currentIndex != -1) { + // Profile is found + mProfilesComboBox->setCurrentIndex(currentIndex); + } + + mLauncherConfig->endGroup(); +} + + +void DataFilesPage::readConfig() +{ + QString profile = mProfilesComboBox->currentText(); + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + mLauncherConfig->beginGroup(profile); + + QStringList childKeys = mLauncherConfig->childKeys(); + QStringList plugins; + + // Sort the child keys numerical instead of alphabetically + // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 + qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); + + foreach (const QString &key, childKeys) { + const QString keyValue = mLauncherConfig->value(key).toString(); + + mDataFilesList->setCheckState(keyValue, Qt::Checked); + } + + qDebug() << plugins; +} + +bool DataFilesPage::showDataFilesWarning() +{ + + QMessageBox msgBox; + msgBox.setWindowTitle("Error detecting Morrowind installation"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(tr("
Could not find the Data Files location

\ + The directory containing the data files was not found.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + if (msgBox.clickedButton() == dirSelectButton) { + + // Show a custom dir selection dialog which only accepts valid dirs + QString selectedDir = FileDialog::getExistingDirectory( + this, tr("Select Data Files Directory"), + QDir::currentPath(), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + // Add the user selected data directory + if (!selectedDir.isEmpty()) { + mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); + mCfgMgr.processPaths(mDataDirs); + } else { + // Cancel from within the dir selection dialog + return false; + } + + } else { + // Cancel + return false; + } + + return true; +} + +bool DataFilesPage::setupDataFiles() +{ + // We use the Configuration Manager to retrieve the configuration values + boost::program_options::variables_map variables; + boost::program_options::options_description desc; + + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) + ("data-local", boost::program_options::value()->default_value("")) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("encoding", boost::program_options::value()->default_value("win1252")); + + boost::program_options::notify(variables); + + mCfgMgr.readConfiguration(variables, desc); + + if (variables["data"].empty()) { + if (!showDataFilesWarning()) + return false; + } else { + mDataDirs = Files::PathContainer(variables["data"].as()); + } + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + mDataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + // Second chance to display the warning, the data= entries are invalid + while (mDataDirs.empty()) { + if (!showDataFilesWarning()) + return false; + } + + // Set the charset for reading the esm/esp files + QString encoding = QString::fromStdString(variables["encoding"].as()); + + Files::PathContainer paths; + paths.insert(paths.end(), mDataDirs.begin(), mDataDirs.end()); + paths.insert(paths.end(), mDataLocal.begin(), mDataLocal.end()); + mDataFilesList->setupDataFiles(paths, encoding); + readConfig(); + return true; +} + +void DataFilesPage::writeConfig(QString profile) +{ + QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); + QDir userPath(pathStr); + + if (!userPath.exists()) { + if (!userPath.mkpath(pathStr)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error creating OpenMW configuration directory"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not create %0

\ + Please make sure you have the right permissions and try again.
").arg(pathStr)); + msgBox.exec(); + + qApp->quit(); + return; + } + } + // Open the OpenMW config as a QFile + QFile file(pathStr.append("openmw.cfg")); + + if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0

\ + Please make sure you have the right permissions and try again.
").arg(file.fileName())); + msgBox.exec(); + + qApp->quit(); + return; + } + + QTextStream in(&file); + QByteArray buffer; + + // Remove all previous entries from config + while (!in.atEnd()) { + QString line = in.readLine(); + if (!line.startsWith("master") && + !line.startsWith("plugin") && + !line.startsWith("data") && + !line.startsWith("data-local")) + { + buffer += line += "\n"; + } + } + + file.close(); + + // Now we write back the other config entries + if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not write to %0

\ + Please make sure you have the right permissions and try again.
").arg(file.fileName())); + msgBox.exec(); + + qApp->quit(); + return; + } + + if (!buffer.isEmpty()) { + file.write(buffer); + } + + QTextStream gameConfig(&file); + + // First write the list of data dirs + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + QString path; + + // data= directories + for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { + path = QString::fromStdString(it->string()); + path.remove(QChar('\"')); + + // Make sure the string is quoted when it contains spaces + if (path.contains(" ")) { + gameConfig << "data=\"" << path << "\"" << endl; + } else { + gameConfig << "data=" << path << endl; + } + } + + // data-local directory + if (!mDataLocal.empty()) { + path = QString::fromStdString(mDataLocal.front().string()); + path.remove(QChar('\"')); + + if (path.contains(" ")) { + gameConfig << "data-local=\"" << path << "\"" << endl; + } else { + gameConfig << "data-local=" << path << endl; + } + } + + + if (profile.isEmpty()) + profile = mProfilesComboBox->currentText(); + + if (profile.isEmpty()) + return; + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + mLauncherConfig->setValue("CurrentProfile", profile); + + // Open the profile-name subgroup + mLauncherConfig->beginGroup(profile); + mLauncherConfig->remove(""); // Clear the subgroup + + // Now write the masters to the configs + const QStringList checkedFiles = mDataFilesList->checkedFiles(); + for(int i=0; i < checkedFiles.size(); i++) + { + if (checkedFiles.at(i).lastIndexOf("esm") != -1) + { + mLauncherConfig->setValue(QString("Master%0").arg(i), checkedFiles.at(i)); + gameConfig << "master=" << checkedFiles.at(i) << endl; + } + else + { + mLauncherConfig->setValue(QString("Plugin%1").arg(i), checkedFiles.at(i)); + gameConfig << "plugin=" << checkedFiles.at(i) << endl; + } + } + + file.close(); + mLauncherConfig->endGroup(); + mLauncherConfig->endGroup(); + mLauncherConfig->sync(); +} + + +void DataFilesPage::newProfile() +{ + if (mNewProfileDialog->exec() == QDialog::Accepted) { + + const QString text = mNewProfileDialog->lineEdit()->text(); + mProfilesComboBox->addItem(text); + + // Copy the currently checked items to cfg + writeConfig(text); + mLauncherConfig->sync(); + + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); + } +} + +void DataFilesPage::updateOkButton(const QString &text) +{ + if (text.isEmpty()) { + mNewProfileDialog->setOkButtonEnabled(false); + return; + } + + (mProfilesComboBox->findText(text) == -1) + ? mNewProfileDialog->setOkButtonEnabled(true) + : mNewProfileDialog->setOkButtonEnabled(false); +} + +void DataFilesPage::deleteProfile() +{ + QString profile = mProfilesComboBox->currentText(); + + if (profile.isEmpty()) + return; + + QMessageBox msgBox(this); + msgBox.setWindowTitle(tr("Delete Profile")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(tr("Are you sure you want to delete %0?").arg(profile)); + + QAbstractButton *deleteButton = + msgBox.addButton(tr("Delete"), QMessageBox::ActionRole); + + msgBox.exec(); + + if (msgBox.clickedButton() == deleteButton) { + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + + // Open the profile-name subgroup + mLauncherConfig->beginGroup(profile); + mLauncherConfig->remove(""); // Clear the subgroup + mLauncherConfig->endGroup(); + mLauncherConfig->endGroup(); + + // Remove the profile from the combobox + mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); + } +} + +void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) +{ + qDebug() << "Profile is changed from: " << previous << " to " << current; + // Prevent the deletion of the default profile + if (current == QLatin1String("Default")) { + mDeleteProfileAction->setEnabled(false); + mProfilesComboBox->setEditEnabled(false); + } else { + mDeleteProfileAction->setEnabled(true); + mProfilesComboBox->setEditEnabled(true); + } + + if (!previous.isEmpty()) { + writeConfig(previous); + mLauncherConfig->sync(); + + if (mProfilesComboBox->currentIndex() == -1) + return; + + } else { + return; + } + + mDataFilesList->uncheckAll(); + readConfig(); +} + +void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) +{ + if (previous.isEmpty()) + return; + + // Save the new profile name + writeConfig(current); + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + + // Open the profile-name subgroup + mLauncherConfig->beginGroup(previous); + mLauncherConfig->remove(""); // Clear the subgroup + mLauncherConfig->endGroup(); + mLauncherConfig->endGroup(); + mLauncherConfig->sync(); + + // Remove the profile from the combobox + mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); + + mDataFilesList->uncheckAll(); + ////mMastersModel->uncheckAll(); + ////mPluginsModel->uncheckAll(); + readConfig(); +} diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp new file mode 100644 index 0000000000..0584de4364 --- /dev/null +++ b/apps/launcher/datafilespage.hpp @@ -0,0 +1,80 @@ +#ifndef DATAFILESPAGE_H +#define DATAFILESPAGE_H + +#include +#include +#include "utils/profilescombobox.hpp" +#include + + +class QTableView; +class QSortFilterProxyModel; +class QSettings; +class QAction; +class QToolBar; +class QMenu; +class ProfilesComboBox; +class DataFilesModel; + +class TextInputDialog; +class DataFilesList; + +namespace Files { struct ConfigurationManager; } + +class DataFilesPage : public QWidget +{ + Q_OBJECT + +public: + DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); + + ProfilesComboBox *mProfilesComboBox; + + void writeConfig(QString profile = QString()); + bool showDataFilesWarning(); + bool setupDataFiles(); + +public slots: + void profileChanged(const QString &previous, const QString ¤t); + void profileRenamed(const QString &previous, const QString ¤t); + void updateOkButton(const QString &text); + + // Action slots + void newProfile(); + void deleteProfile(); +// void moveUp(); +// void moveDown(); +// void moveTop(); +// void moveBottom(); + +private: + DataFilesList *mDataFilesList; + + QToolBar *mProfileToolBar; + + QAction *mNewProfileAction; + QAction *mDeleteProfileAction; + +// QAction *mMoveUpAction; +// QAction *mMoveDownAction; +// QAction *mMoveTopAction; +// QAction *mMoveBottomAction; + + Files::ConfigurationManager &mCfgMgr; + Files::PathContainer mDataDirs; + Files::PathContainer mDataLocal; + + QSettings *mLauncherConfig; + + TextInputDialog *mNewProfileDialog; + +// const QStringList checkedPlugins(); +// const QStringList selectedMasters(); + + void createActions(); + void setupConfig(); + void readConfig(); + +}; + +#endif diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 7914650fe9..674ccdf672 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,10 +1,9 @@ #include -#include - #include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" +#include "datafilespage.hpp" MainDialog::MainDialog() { @@ -124,16 +123,16 @@ void MainDialog::createPages() { mPlayPage = new PlayPage(this); mGraphicsPage = new GraphicsPage(mCfgMgr, this); - mDataFilesList = new DataFilesList(mCfgMgr, this); + mDataFilesPage = new DataFilesPage(mCfgMgr, this); // Set the combobox of the play page to imitate the combobox on the datafilespage - mPlayPage->mProfilesComboBox->setModel(mDataFilesList->mProfilesComboBox->model()); - mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesList->mProfilesComboBox->currentIndex()); + mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); + mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget mPagesWidget->addWidget(mPlayPage); mPagesWidget->addWidget(mGraphicsPage); - mPagesWidget->addWidget(mDataFilesList); + mPagesWidget->addWidget(mDataFilesPage); // Select the first page mIconWidget->setCurrentItem(mIconWidget->item(0), QItemSelectionModel::Select); @@ -142,9 +141,9 @@ void MainDialog::createPages() connect(mPlayPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), - mDataFilesList->mProfilesComboBox, SLOT(setCurrentIndex(int))); + mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); - connect(mDataFilesList->mProfilesComboBox, + connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); @@ -190,7 +189,7 @@ bool MainDialog::setup() } // Setup the Data Files page - if (!mDataFilesList->setupDataFiles()) { + if (!mDataFilesPage->setupDataFiles()) { return false; } @@ -208,7 +207,7 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) void MainDialog::closeEvent(QCloseEvent *event) { // Now write all config files - mDataFilesList->writeConfig(); + mDataFilesPage->writeConfig(); mGraphicsPage->writeConfig(); // Save user settings @@ -221,7 +220,7 @@ void MainDialog::closeEvent(QCloseEvent *event) void MainDialog::play() { // First do a write of all the configs, just to be sure - mDataFilesList->writeConfig(); + mDataFilesPage->writeConfig(); mGraphicsPage->writeConfig(); // Save user settings diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 5a39c11a99..bf98011cc4 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -15,7 +15,7 @@ class QString; class PlayPage; class GraphicsPage; -class DataFilesList; +class DataFilesPage; class MainDialog : public QMainWindow { @@ -39,7 +39,7 @@ private: PlayPage *mPlayPage; GraphicsPage *mGraphicsPage; - DataFilesList *mDataFilesList; + DataFilesPage *mDataFilesPage; Files::ConfigurationManager mCfgMgr; Settings::Manager mSettings; diff --git a/components/fileorderlist/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp similarity index 100% rename from components/fileorderlist/utils/profilescombobox.cpp rename to apps/launcher/utils/profilescombobox.cpp diff --git a/components/fileorderlist/utils/profilescombobox.hpp b/apps/launcher/utils/profilescombobox.hpp similarity index 100% rename from components/fileorderlist/utils/profilescombobox.hpp rename to apps/launcher/utils/profilescombobox.hpp diff --git a/components/fileorderlist/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp similarity index 100% rename from components/fileorderlist/utils/textinputdialog.cpp rename to apps/launcher/utils/textinputdialog.cpp diff --git a/components/fileorderlist/utils/textinputdialog.hpp b/apps/launcher/utils/textinputdialog.hpp similarity index 100% rename from components/fileorderlist/utils/textinputdialog.hpp rename to apps/launcher/utils/textinputdialog.hpp diff --git a/apps/opencs/view/doc/opendialog.cpp b/apps/opencs/view/doc/opendialog.cpp index f51cbadb97..9a5feb23a7 100644 --- a/apps/opencs/view/doc/opendialog.cpp +++ b/apps/opencs/view/doc/opendialog.cpp @@ -10,7 +10,42 @@ OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) QVBoxLayout *layout = new QVBoxLayout(this); mFileSelector = new DataFilesList(mCfgMgr, this); layout->addWidget(mFileSelector); - mFileSelector->setupDataFiles(); + + //FIXME - same as DataFilesPage::setupDataFiles + // We use the Configuration Manager to retrieve the configuration values + boost::program_options::variables_map variables; + boost::program_options::options_description desc; + + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) + ("data-local", boost::program_options::value()->default_value("")) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("encoding", boost::program_options::value()->default_value("win1252")); + + boost::program_options::notify(variables); + + mCfgMgr.readConfiguration(variables, desc); + + Files::PathContainer mDataDirs, mDataLocal; + if (!variables["data"].empty()) { + mDataDirs = Files::PathContainer(variables["data"].as()); + } + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + mDataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + // Set the charset for reading the esm/esp files + QString encoding = QString::fromStdString(variables["encoding"].as()); + + Files::PathContainer dataDirs; + dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end()); + dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end()); + mFileSelector->setupDataFiles(dataDirs, encoding); buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); @@ -23,5 +58,5 @@ OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) void OpenDialog::getFileList(std::vector& paths) { - mFileSelector->getSelectedFiles(paths); + mFileSelector->selectedFiles(paths); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 63a2276217..00342e2ac8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -71,7 +71,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui) if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (fileorderlist datafileslist model/modelitem model/datafilesmodel model/esm/esmfile - utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort + utils/filedialog utils/lineedit utils/naturalsort ) include(${QT_USE_FILE}) diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index f346407a90..38e0bfb1a5 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -6,11 +6,9 @@ #include "model/datafilesmodel.hpp" #include "model/esm/esmfile.hpp" -#include "utils/profilescombobox.hpp" #include "utils/filedialog.hpp" #include "utils/lineedit.hpp" #include "utils/naturalsort.hpp" -#include "utils/textinputdialog.hpp" #include "datafileslist.hpp" @@ -137,32 +135,10 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) sizeList << 175 << 200; splitter->setSizes(sizeList); - // Bottom part with profile options - QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); - - mProfilesComboBox = new ProfilesComboBox(this); - mProfilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); - mProfilesComboBox->setInsertPolicy(QComboBox::NoInsert); - mProfilesComboBox->setDuplicatesEnabled(false); - mProfilesComboBox->setEditEnabled(false); - - mProfileToolBar = new QToolBar(this); - mProfileToolBar->setMovable(false); - mProfileToolBar->setIconSize(QSize(16, 16)); - - mProfileToolBar->addWidget(profileLabel); - mProfileToolBar->addWidget(mProfilesComboBox); - QVBoxLayout *pageLayout = new QVBoxLayout(this); pageLayout->addWidget(filterToolBar); pageLayout->addWidget(splitter); - pageLayout->addWidget(mProfileToolBar); - - // Create a dialog for the new profile name input - mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); - - connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); @@ -173,11 +149,7 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); - connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); - createActions(); - setupConfig(); } void DataFilesList::createActions() @@ -187,22 +159,6 @@ void DataFilesList::createActions() refreshAction->setShortcut(QKeySequence(tr("F5"))); connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); - // Profile actions - mNewProfileAction = new QAction(QIcon::fromTheme("document-new"), tr("&New Profile"), this); - mNewProfileAction->setToolTip(tr("New Profile")); - mNewProfileAction->setShortcut(QKeySequence(tr("Ctrl+N"))); - connect(mNewProfileAction, SIGNAL(triggered()), this, SLOT(newProfile())); - - mDeleteProfileAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete Profile"), this); - mDeleteProfileAction->setToolTip(tr("Delete Profile")); - mDeleteProfileAction->setShortcut(QKeySequence(tr("Delete"))); - connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); - - // Add the newly created actions to the toolbar - mProfileToolBar->addSeparator(); - mProfileToolBar->addAction(mNewProfileAction); - mProfileToolBar->addAction(mDeleteProfileAction); - // Context menu actions mCheckAction = new QAction(tr("Check selected"), this); connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check())); @@ -218,223 +174,16 @@ void DataFilesList::createActions() } -void DataFilesList::setupConfig() +bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString encoding) { - // Open our config file - QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); - mLauncherConfig = new QSettings(config, QSettings::IniFormat); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - QStringList profiles = mLauncherConfig->childGroups(); - - // Add the profiles to the combobox - foreach (const QString &profile, profiles) { - - if (profile.contains(QRegExp("[^a-zA-Z0-9_]"))) - continue; // Profile name contains garbage - - - qDebug() << "adding " << profile; - mProfilesComboBox->addItem(profile); - } - - // Add a default profile - if (mProfilesComboBox->findText(QString("Default")) == -1) { - mProfilesComboBox->addItem(QString("Default")); - } - - QString currentProfile = mLauncherConfig->value("CurrentProfile").toString(); - - if (currentProfile.isEmpty()) { - // No current profile selected - currentProfile = "Default"; - } - - const int currentIndex = mProfilesComboBox->findText(currentProfile); - if (currentIndex != -1) { - // Profile is found - mProfilesComboBox->setCurrentIndex(currentIndex); - } - - mLauncherConfig->endGroup(); -} - - -void DataFilesList::readConfig() -{ - // Don't read the config if no masters are found - if (mMastersModel->rowCount() < 1) - return; - - QString profile = mProfilesComboBox->currentText(); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - mLauncherConfig->beginGroup(profile); - - QStringList childKeys = mLauncherConfig->childKeys(); - QStringList plugins; - - // Sort the child keys numerical instead of alphabetically - // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 - qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); - - foreach (const QString &key, childKeys) { - const QString keyValue = mLauncherConfig->value(key).toString(); - - if (key.startsWith("Plugin")) { - //QStringList checked = mPluginsModel->checkedItems(); - EsmFile *file = mPluginsModel->findItem(keyValue); - QModelIndex index = mPluginsModel->indexFromItem(file); - - mPluginsModel->setCheckState(index, Qt::Checked); - // Move the row to the top of te view - //mPluginsModel->moveRow(index.row(), checked.count()); - plugins << keyValue; - } - - if (key.startsWith("Master")) { - EsmFile *file = mMastersModel->findItem(keyValue); - mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); - } - } - - qDebug() << plugins; - - -// // Set the checked item positions -// const QStringList checked = mPluginsModel->checkedItems(); -// for (int i = 0; i < plugins.size(); ++i) { -// EsmFile *file = mPluginsModel->findItem(plugins.at(i)); -// QModelIndex index = mPluginsModel->indexFromItem(file); -// mPluginsModel->moveRow(index.row(), i); -// qDebug() << "Moving: " << plugins.at(i) << " from: " << index.row() << " to: " << i << " count: " << checked.count(); - -// } - - // Iterate over the plugins to set their checkstate and position -// for (int i = 0; i < plugins.size(); ++i) { -// const QString plugin = plugins.at(i); - -// const QList pluginList = mPluginsModel->findItems(plugin); - -// if (!pluginList.isEmpty()) -// { -// foreach (const QStandardItem *currentPlugin, pluginList) { -// mPluginsModel->setData(currentPlugin->index(), Qt::Checked, Qt::CheckStateRole); - -// // Move the plugin to the position specified in the config file -// mPluginsModel->insertRow(i, mPluginsModel->takeRow(currentPlugin->row())); -// } -// } -// } - -} - -bool DataFilesList::showDataFilesWarning() -{ - - QMessageBox msgBox; - msgBox.setWindowTitle("Error detecting Morrowind installation"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("
Could not find the Data Files location

\ - The directory containing the data files was not found.

\ - Press \"Browse...\" to specify the location manually.
")); - - QAbstractButton *dirSelectButton = - msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); - - msgBox.exec(); - - if (msgBox.clickedButton() == dirSelectButton) { - - // Show a custom dir selection dialog which only accepts valid dirs - QString selectedDir = FileDialog::getExistingDirectory( - this, tr("Select Data Files Directory"), - QDir::currentPath(), - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - - // Add the user selected data directory - if (!selectedDir.isEmpty()) { - mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); - mCfgMgr.processPaths(mDataDirs); - } else { - // Cancel from within the dir selection dialog - return false; - } - - } else { - // Cancel - return false; - } - - return true; -} - -bool DataFilesList::setupDataFiles() -{ - // We use the Configuration Manager to retrieve the configuration values - boost::program_options::variables_map variables; - boost::program_options::options_description desc; - - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) - ("data-local", boost::program_options::value()->default_value("")) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("encoding", boost::program_options::value()->default_value("win1252")); - - boost::program_options::notify(variables); - - mCfgMgr.readConfiguration(variables, desc); - - if (variables["data"].empty()) { - if (!showDataFilesWarning()) - return false; - } else { - mDataDirs = Files::PathContainer(variables["data"].as()); - } - - std::string local = variables["data-local"].as(); - if (!local.empty()) { - mDataLocal.push_back(Files::PathContainer::value_type(local)); - } - - mCfgMgr.processPaths(mDataDirs); - mCfgMgr.processPaths(mDataLocal); - - // Second chance to display the warning, the data= entries are invalid - while (mDataDirs.empty()) { - if (!showDataFilesWarning()) - return false; - } - // Set the charset for reading the esm/esp files - QString encoding = QString::fromStdString(variables["encoding"].as()); if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { mMastersModel->setEncoding(encoding); mPluginsModel->setEncoding(encoding); } // Add the paths to the respective models - for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { - QString path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - mMastersModel->addMasters(path); - mPluginsModel->addPlugins(path); - } - - // Same for the data-local paths - for (Files::PathContainer::iterator it = mDataLocal.begin(); it != mDataLocal.end(); ++it) { + for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { QString path = QString::fromStdString(it->string()); path.remove(QChar('\"')); mMastersModel->addMasters(path); @@ -446,12 +195,10 @@ bool DataFilesList::setupDataFiles() // mMastersTable->sortByColumn(3, Qt::AscendingOrder); // mPluginsTable->sortByColumn(3, Qt::AscendingOrder); - - readConfig(); return true; } -void DataFilesList::getSelectedFiles(std::vector& paths) +void DataFilesList::selectedFiles(std::vector& paths) { QStringList masterPaths = mMastersModel->checkedItemsPaths(); foreach (const QString &path, masterPaths) @@ -467,225 +214,6 @@ void DataFilesList::getSelectedFiles(std::vector& paths } } -void DataFilesList::writeConfig(QString profile) -{ - // Don't overwrite the config if no masters are found - if (mMastersModel->rowCount() < 1) - return; - - QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); - QDir userPath(pathStr); - - if (!userPath.exists()) { - if (!userPath.mkpath(pathStr)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error creating OpenMW configuration directory"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not create %0

\ - Please make sure you have the right permissions and try again.
").arg(pathStr)); - msgBox.exec(); - - qApp->quit(); - return; - } - } - // Open the OpenMW config as a QFile - QFile file(pathStr.append("openmw.cfg")); - - if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { - // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not open or create %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); - msgBox.exec(); - - qApp->quit(); - return; - } - - QTextStream in(&file); - QByteArray buffer; - - // Remove all previous entries from config - while (!in.atEnd()) { - QString line = in.readLine(); - if (!line.startsWith("master") && - !line.startsWith("plugin") && - !line.startsWith("data") && - !line.startsWith("data-local")) - { - buffer += line += "\n"; - } - } - - file.close(); - - // Now we write back the other config entries - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not write to %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); - msgBox.exec(); - - qApp->quit(); - return; - } - - if (!buffer.isEmpty()) { - file.write(buffer); - } - - QTextStream gameConfig(&file); - - // First write the list of data dirs - mCfgMgr.processPaths(mDataDirs); - mCfgMgr.processPaths(mDataLocal); - - QString path; - - // data= directories - for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { - path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - - // Make sure the string is quoted when it contains spaces - if (path.contains(" ")) { - gameConfig << "data=\"" << path << "\"" << endl; - } else { - gameConfig << "data=" << path << endl; - } - } - - // data-local directory - if (!mDataLocal.empty()) { - path = QString::fromStdString(mDataLocal.front().string()); - path.remove(QChar('\"')); - - if (path.contains(" ")) { - gameConfig << "data-local=\"" << path << "\"" << endl; - } else { - gameConfig << "data-local=" << path << endl; - } - } - - - if (profile.isEmpty()) - profile = mProfilesComboBox->currentText(); - - if (profile.isEmpty()) - return; - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - mLauncherConfig->setValue("CurrentProfile", profile); - - // Open the profile-name subgroup - mLauncherConfig->beginGroup(profile); - mLauncherConfig->remove(""); // Clear the subgroup - - // Now write the masters to the configs - const QStringList masters = mMastersModel->checkedItems(); - - // We don't use foreach because we need i - for (int i = 0; i < masters.size(); ++i) { - const QString currentMaster = masters.at(i); - - mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster); - gameConfig << "master=" << currentMaster << endl; - - } - - // And finally write all checked plugins - const QStringList plugins = mPluginsModel->checkedItems(); - - for (int i = 0; i < plugins.size(); ++i) { - const QString currentPlugin = plugins.at(i); - mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin); - gameConfig << "plugin=" << currentPlugin << endl; - } - - file.close(); - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - mLauncherConfig->sync(); -} - - -void DataFilesList::newProfile() -{ - if (mNewProfileDialog->exec() == QDialog::Accepted) { - - const QString text = mNewProfileDialog->lineEdit()->text(); - mProfilesComboBox->addItem(text); - - // Copy the currently checked items to cfg - writeConfig(text); - mLauncherConfig->sync(); - - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); - } -} - -void DataFilesList::updateOkButton(const QString &text) -{ - if (text.isEmpty()) { - mNewProfileDialog->setOkButtonEnabled(false); - return; - } - - (mProfilesComboBox->findText(text) == -1) - ? mNewProfileDialog->setOkButtonEnabled(true) - : mNewProfileDialog->setOkButtonEnabled(false); -} - -void DataFilesList::deleteProfile() -{ - QString profile = mProfilesComboBox->currentText(); - - if (profile.isEmpty()) - return; - - QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Delete Profile")); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("Are you sure you want to delete %0?").arg(profile)); - - QAbstractButton *deleteButton = - msgBox.addButton(tr("Delete"), QMessageBox::ActionRole); - - msgBox.exec(); - - if (msgBox.clickedButton() == deleteButton) { - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - - // Open the profile-name subgroup - mLauncherConfig->beginGroup(profile); - mLauncherConfig->remove(""); // Clear the subgroup - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - - // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); - } -} - void DataFilesList::check() { // Check the current selection @@ -733,8 +261,6 @@ void DataFilesList::refresh() // Refresh the plugins table mPluginsTable->scrollToTop(); - writeConfig(); - readConfig(); } @@ -767,70 +293,18 @@ void DataFilesList::setCheckState(QModelIndex index) } +void DataFilesList::uncheckAll() +{ + mMastersModel->uncheckAll(); + mPluginsModel->uncheckAll(); +} + void DataFilesList::filterChanged(const QString filter) { QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); mPluginsProxyModel->setFilterRegExp(regExp); } -void DataFilesList::profileChanged(const QString &previous, const QString ¤t) -{ - qDebug() << "Profile is changed from: " << previous << " to " << current; - // Prevent the deletion of the default profile - if (current == QLatin1String("Default")) { - mDeleteProfileAction->setEnabled(false); - mProfilesComboBox->setEditEnabled(false); - } else { - mDeleteProfileAction->setEnabled(true); - mProfilesComboBox->setEditEnabled(true); - } - - if (!previous.isEmpty()) { - writeConfig(previous); - mLauncherConfig->sync(); - - if (mProfilesComboBox->currentIndex() == -1) - return; - - } else { - return; - } - - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); - readConfig(); -} - -void DataFilesList::profileRenamed(const QString &previous, const QString ¤t) -{ - if (previous.isEmpty()) - return; - - // Save the new profile name - writeConfig(current); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - - // Open the profile-name subgroup - mLauncherConfig->beginGroup(previous); - mLauncherConfig->remove(""); // Clear the subgroup - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - mLauncherConfig->sync(); - - // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); - readConfig(); -} - void DataFilesList::showContextMenu(const QPoint &point) { // Make sure there are plugins in the view @@ -858,3 +332,22 @@ void DataFilesList::showContextMenu(const QPoint &point) // Show menu mContextMenu->exec(globalPos); } + +void DataFilesList::setCheckState(const QString& element, Qt::CheckState state) +{ + EsmFile *file = mPluginsModel->findItem(element); + if (file) + { + mPluginsModel->setCheckState(mPluginsModel->indexFromItem(file), Qt::Checked); + } + else + { + file = mMastersModel->findItem(element); + mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); + } +} + +QStringList DataFilesList::checkedFiles() +{ + return mMastersModel->checkedItems() + mPluginsModel->checkedItems(); +} \ No newline at end of file diff --git a/components/fileorderlist/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp index 7bdb5e0571..4b158d316d 100644 --- a/components/fileorderlist/datafileslist.hpp +++ b/components/fileorderlist/datafileslist.hpp @@ -3,7 +3,6 @@ #include #include -#include "utils/profilescombobox.hpp" #include @@ -27,25 +26,20 @@ class DataFilesList : public QWidget public: DataFilesList(Files::ConfigurationManager& cfg, QWidget *parent = 0); - ProfilesComboBox *mProfilesComboBox; - - void writeConfig(QString profile = QString()); - bool showDataFilesWarning(); - bool setupDataFiles(); - void getSelectedFiles(std::vector& paths); + bool setupDataFiles(Files::PathContainer dataDirs, const QString encoding); + void selectedFiles(std::vector& paths); + void uncheckAll(); + QStringList checkedFiles(); + void setCheckState(const QString& element, Qt::CheckState); + public slots: void setCheckState(QModelIndex index); void filterChanged(const QString filter); void showContextMenu(const QPoint &point); - void profileChanged(const QString &previous, const QString ¤t); - void profileRenamed(const QString &previous, const QString ¤t); - void updateOkButton(const QString &text); // Action slots - void newProfile(); - void deleteProfile(); // void moveUp(); // void moveDown(); // void moveTop(); @@ -63,12 +57,8 @@ private: QTableView *mMastersTable; QTableView *mPluginsTable; - QToolBar *mProfileToolBar; QMenu *mContextMenu; - QAction *mNewProfileAction; - QAction *mDeleteProfileAction; - // QAction *mMoveUpAction; // QAction *mMoveDownAction; // QAction *mMoveTopAction; @@ -77,20 +67,11 @@ private: QAction *mUncheckAction; Files::ConfigurationManager &mCfgMgr; - Files::PathContainer mDataDirs; - Files::PathContainer mDataLocal; - - QSettings *mLauncherConfig; - - TextInputDialog *mNewProfileDialog; // const QStringList checkedPlugins(); // const QStringList selectedMasters(); void createActions(); - void setupConfig(); - void readConfig(); - }; #endif From 5ee298cdc14c0f653c377fa4c676a2487e877d54 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 14:08:38 -0800 Subject: [PATCH 0233/1483] Make sure the player updates last --- apps/openmw/mwmechanics/actors.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c1f552ae49..e829d46799 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -258,14 +258,19 @@ namespace MWMechanics if(!paused) { - std::vector > movement; + PtrControllerMap::iterator player(mActors.end()); for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 vector = iter->second.update(duration); - if(vector!=Ogre::Vector3::ZERO) - movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); + if(iter->first.getRefData().getHandle() == "player") + { + /* Make sure player updates last (in case a cell transition occurs) */ + player = iter; + continue; + } + iter->second.update(duration); } - MWBase::Environment::get().getWorld()->doPhysics (movement, duration); + if(player != mActors.end()) + player->second.update(duration); } } From 596628d339472e19864d7433675e1d4e146a04d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Feb 2013 23:13:01 +0100 Subject: [PATCH 0234/1483] Fix terrain derived data update (bug 534, bug 544) --- apps/openmw/mwrender/terrain.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index e5a1362d7b..5b24bbd45a 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwworld/esmstore.hpp" @@ -151,6 +152,16 @@ namespace MWRender mTerrainGroup.loadTerrain(terrainX, terrainY, true); + // when loading from a heightmap, Ogre::Terrain does not update the derived data (normal map, LOD) + // synchronously, even if we supply synchronous = true parameter to loadTerrain. + // the following to be the only way to make sure derived data is ready when rendering the next frame. + while (mTerrainGroup.isDerivedDataUpdateInProgress()) + { + // we need to wait for this to finish + OGRE_THREAD_SLEEP(5); + Root::getSingleton().getWorkQueue()->processResponses(); + } + Terrain* terrain = mTerrainGroup.getTerrain(terrainX, terrainY); initTerrainBlendMaps(terrain, cellX, cellY, From 58cf182db2df6e47e8e98e35c2c49d157857c88b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 00:21:29 +0100 Subject: [PATCH 0235/1483] better place for syncing --- apps/openmw/mwrender/terrain.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 5b24bbd45a..f4ad261c5a 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -152,16 +152,6 @@ namespace MWRender mTerrainGroup.loadTerrain(terrainX, terrainY, true); - // when loading from a heightmap, Ogre::Terrain does not update the derived data (normal map, LOD) - // synchronously, even if we supply synchronous = true parameter to loadTerrain. - // the following to be the only way to make sure derived data is ready when rendering the next frame. - while (mTerrainGroup.isDerivedDataUpdateInProgress()) - { - // we need to wait for this to finish - OGRE_THREAD_SLEEP(5); - Root::getSingleton().getWorkQueue()->processResponses(); - } - Terrain* terrain = mTerrainGroup.getTerrain(terrainX, terrainY); initTerrainBlendMaps(terrain, cellX, cellY, @@ -189,6 +179,16 @@ namespace MWRender } } + // when loading from a heightmap, Ogre::Terrain does not update the derived data (normal map, LOD) + // synchronously, even if we supply synchronous = true parameter to loadTerrain. + // the following to be the only way to make sure derived data is ready when rendering the next frame. + while (mTerrainGroup.isDerivedDataUpdateInProgress()) + { + // we need to wait for this to finish + OGRE_THREAD_SLEEP(5); + Root::getSingleton().getWorkQueue()->processResponses(); + } + mTerrainGroup.freeTemporaryResources(); } From a29919d02dd08a58114c22750bc49185e7fe704a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 00:39:56 +0100 Subject: [PATCH 0236/1483] restored global map --- apps/openmw/mwrender/localmap.cpp | 47 +++++++++++-------------------- apps/openmw/mwrender/localmap.hpp | 11 +------- 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index ccad0a5e8f..e0b7d9a119 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -191,6 +191,20 @@ void LocalMap::render(const float x, const float y, mCellCamera->setFarClipDistance(0); // infinite mCellCamera->setOrthoWindow(xw, yw); + mCellCamera->setPosition(Vector3(x, zhigh+100000, y)); + + // disable fog (only necessary for fixed function, the shader based + // materials already do this through local_map material configuration) + float oldFogStart = mRendering->getScene()->getFogStart(); + float oldFogEnd = mRendering->getScene()->getFogEnd(); + Ogre::ColourValue oldFogColour = mRendering->getScene()->getFogColour(); + mRendering->getScene()->setFog(FOG_NONE); + + // set up lighting + Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); + mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); + mRenderingManager->disableLights(true); + mLight->setVisible(true); TexturePtr tex; // try loading from memory @@ -216,8 +230,6 @@ void LocalMap::render(const float x, const float y, RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); - mCameraSettings[rtt] = Vector3(x, zhigh+100000, y); - rtt->setAutoUpdated(false); Viewport* vp = rtt->addViewport(mCellCamera); vp->setOverlaysEnabled(false); @@ -228,8 +240,7 @@ void LocalMap::render(const float x, const float y, // use fallback techniques without shadows and without mrt vp->setMaterialScheme("local_map"); - rtt->setAutoUpdated(true); - rtt->addListener(this); + rtt->update(); // create "fog of war" texture TexturePtr tex2 = TextureManager::getSingleton().createManual( @@ -260,36 +271,12 @@ void LocalMap::render(const float x, const float y, //rtt->writeContentsToFile("./" + texture + ".jpg"); } } -} - -void LocalMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ - // disable fog (only necessary for fixed function, the shader based - // materials already do this through local_map material configuration) - mOldFogStart = mRendering->getScene()->getFogStart(); - mOldFogEnd = mRendering->getScene()->getFogEnd(); - mOldFogClr = mRendering->getScene()->getFogColour(); - mRendering->getScene()->setFog(FOG_NONE); - - mOldAmbient = mRendering->getScene()->getAmbientLight(); - mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); - - mCellCamera->setPosition(mCameraSettings[evt.source]); - - mRenderingManager->disableLights(true); - mLight->setVisible(true); - evt.source->setAutoUpdated(false); -} - -void LocalMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ mRenderingManager->enableLights(true); mLight->setVisible(false); - evt.source->removeListener(this); // re-enable fog - mRendering->getScene()->setFog(FOG_LINEAR, mOldFogClr, 0, mOldFogStart, mOldFogEnd); - mRendering->getScene()->setAmbientLight(mOldAmbient); + mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); + mRendering->getScene()->setAmbientLight(oldAmbient); } void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index afdf4b6e57..9c82258f95 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -5,7 +5,6 @@ #include #include -#include namespace MWWorld { @@ -19,7 +18,7 @@ namespace MWRender /// /// \brief Local map rendering /// - class LocalMap : public Ogre::RenderTargetListener + class LocalMap { public: LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering); @@ -71,9 +70,6 @@ namespace MWRender */ bool isPositionExplored (float nX, float nY, int x, int y, bool interior); - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - private: OEngine::Render::OgreRenderer* mRendering; MWRender::RenderingManager* mRenderingManager; @@ -122,11 +118,6 @@ namespace MWRender Ogre::AxisAlignedBox mBounds; std::string mInteriorName; - Ogre::ColourValue mOldFogClr; - Ogre::ColourValue mOldAmbient; - float mOldFogStart; - float mOldFogEnd; - // maps texture name to according camera settings std::map mCameraSettings; }; From 3fe5757770b9abecd02cbb288f371c8208f92892 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Feb 2013 10:28:49 +0100 Subject: [PATCH 0237/1483] updated changelog for 0.21.0 again --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index 91690ff574..3124744c30 100644 --- a/readme.txt +++ b/readme.txt @@ -114,8 +114,10 @@ Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin Bug #524: Beast races are able to wear shoes Bug #527: Background music fails to play Bug #533: The arch at Gnisis entrance is not displayed +Bug #534: Terrain gets its correct shape only some time after the cell is loaded Bug #536: The same entry can be added multiple times to the journal Bug #539: Race selection is broken +Bug #544: Terrain normal map corrupt when the map is rendered Feature #39: Video Playback Feature #151: ^-escape sequences in text output Feature #392: Add AI related script functions From cfceb450095db1ea1a8d91c21f86ecc81a85c6b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Feb 2013 11:53:48 +0100 Subject: [PATCH 0238/1483] adjusted gcc settings again to avoid problems with older compiler versions --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 165db6b792..577b6f6b2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,7 +306,7 @@ endif() # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++03 -pedantic -Wno-long-long) + add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long) # Silence warnings in OGRE headers. Remove once OGRE got fixed! add_definitions (-Wno-ignored-qualifiers) From c409f1184e9667d193eda048980329c9edbe1c71 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Feb 2013 12:19:06 +0100 Subject: [PATCH 0239/1483] cleaned up object movement and fixed a bug regarding local scripts --- apps/openmw/mwworld/worldimp.cpp | 64 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 24d139b377..609b6582d0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -302,26 +302,26 @@ namespace MWWorld { return mGlobalVariables->getGlobals(); } - + std::string World::getCurrentCellName () const { std::string name; Ptr::CellStore *cell = mWorldScene->getCurrentCell(); if (cell->mCell->isExterior()) - { + { if (cell->mCell->mName != "") - { + { name = cell->mCell->mName; - } - else - { + } + else + { const ESM::Region* region = MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); if (region) name = region->mName; else - { + { const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().search("sDefaultCellname"); @@ -331,13 +331,13 @@ namespace MWWorld name = "Wilderness"; } - } - } - else - { + } + } + else + { name = cell->mCell->mName; - } - + } + return name; } @@ -426,12 +426,12 @@ namespace MWWorld if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); - + if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); } } - + void World::removeContainerScripts(const Ptr& reference) { if( reference.getTypeName()==typeid (ESM::Container).name() || @@ -456,7 +456,7 @@ namespace MWWorld if (reference.getRefData().isEnabled()) { reference.getRefData().disable(); - + if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); } @@ -687,14 +687,14 @@ namespace MWWorld void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { ESM::Position &pos = ptr.getRefData().getPosition(); - pos.pos[0] = x, pos.pos[1] = y, pos.pos[2] = z; + pos.pos[0] = x; + pos.pos[1] = y; + pos.pos[2] = z; Ogre::Vector3 vec(x, y, z); CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; - - removeContainerScripts(ptr); if (*currCell != newCell) { @@ -707,7 +707,8 @@ namespace MWWorld int cellY = newCell.mCell->getGridY(); mWorldScene->changeCell(cellX, cellY, pos, false); } - else { + else + { if (!mWorldScene->isCellActive(*currCell)) copyObjectToCell(ptr, newCell, pos); else if (!mWorldScene->isCellActive(newCell)) @@ -715,6 +716,7 @@ namespace MWWorld MWWorld::Class::get(ptr).copyToCell(ptr, newCell); mWorldScene->removeObjectFromScene(ptr); mLocalScripts.remove(ptr); + removeContainerScripts (ptr); haveToMove = false; } else @@ -722,10 +724,18 @@ namespace MWWorld MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); - addContainerScripts(copy, &newCell); - mRendering->moveObjectToCell(copy, vec, currCell); + std::string script = + MWWorld::Class::get(ptr).getScript(ptr); + if (!script.empty()) + { + mLocalScripts.remove(ptr); + removeContainerScripts (ptr); + mLocalScripts.add(script, copy); + addContainerScripts (copy, &newCell); + } + if (MWWorld::Class::get(ptr).isActor()) { MWBase::MechanicsManager *mechMgr = @@ -734,16 +744,6 @@ namespace MWWorld mechMgr->removeActor(ptr); mechMgr->addActor(copy); } - else - { - std::string script = - MWWorld::Class::get(ptr).getScript(ptr); - if (!script.empty()) - { - mLocalScripts.remove(ptr); - mLocalScripts.add(script, copy); - } - } } ptr.getRefData().setCount(0); } From 3772cd9257cf127fdbb476d169e831536852572a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 14:29:46 +0100 Subject: [PATCH 0240/1483] Refraction can be disabled separately now --- apps/openmw/mwgui/settingswindow.cpp | 6 ++++ apps/openmw/mwgui/settingswindow.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 22 +++++++++----- apps/openmw/mwrender/water.cpp | 10 ++++-- files/materials/core.h | 6 ---- files/materials/objects.shader | 11 ++----- files/materials/terrain.shader | 16 ++++------ files/materials/water.mat | 3 ++ files/materials/water.shader | 37 ++++++++++++++--------- files/mygui/openmw_settings_window.layout | 7 +++++ files/settings-default.cfg | 6 ++-- 11 files changed, 72 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c5c6eada26..343c96cece 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -123,6 +123,7 @@ namespace MWGui getWidget(mInvertYButton, "InvertYButton"); getWidget(mUISensitivitySlider, "UISensitivitySlider"); getWidget(mCameraSensitivitySlider, "CameraSensitivitySlider"); + getWidget(mRefractionButton, "RefractionButton"); mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -133,6 +134,7 @@ namespace MWGui mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mWaterShaderButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mRefractionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectObjectsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectTerrainButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectActorsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -248,6 +250,8 @@ namespace MWGui mShadersButton->setCaption (Settings::Manager::getBool("shaders", "Objects") ? "on" : "off"); mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); + mRefractionButton->setCaption (Settings::Manager::getBool("refraction", "Water") ? "on" : "off"); + if (!MWRender::RenderingManager::waterShaderSupported()) { mWaterShaderButton->setEnabled(false); @@ -376,6 +380,8 @@ namespace MWGui { if (_sender == mWaterShaderButton) Settings::Manager::setBool("shader", "Water", newState); + else if (_sender == mRefractionButton) + Settings::Manager::setBool("refraction", "Water", newState); else if (_sender == mUnderwaterButton) { Settings::Manager::setBool("underwater effect", "Water", newState); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 8ca3ad758b..55cc0a8704 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -51,6 +51,7 @@ namespace MWGui MyGUI::Button* mShadersButton; MyGUI::Button* mShaderModeButton; MyGUI::Button* mUnderwaterButton; + MyGUI::Button* mRefractionButton; MyGUI::Button* mShadowsEnabledButton; MyGUI::Button* mShadowsLargeDistance; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aa73bc49bb..69f3914e59 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -135,8 +135,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); - sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty(new sh::FloatValue( - 1.f))); + sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); applyCompositors(); @@ -757,6 +756,7 @@ Compositors* RenderingManager::getCompositors() void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) { bool changeRes = false; + bool rebuild = false; // rebuild static geometry (necessary after any material changes) for (Settings::CategorySettingVector::const_iterator it=settings.begin(); it != settings.end(); ++it) { @@ -794,18 +794,23 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec applyCompositors(); sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - mObjects.rebuildStaticGeometry (); + rebuild = true; mRendering.getViewport ()->setClearEveryFrame (true); } + else if (it->second == "refraction" && it->first == "Water") + { + sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); + rebuild = true; + } else if (it->second == "underwater effect" && it->first == "Water") { sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); - mObjects.rebuildStaticGeometry (); + rebuild = true; } else if (it->second == "shaders" && it->first == "Objects") { sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); - mObjects.rebuildStaticGeometry (); + rebuild = true; } else if (it->second == "shader mode" && it->first == "General") { @@ -818,13 +823,13 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec else lang = sh::Language_CG; sh::Factory::getInstance ().setCurrentLanguage (lang); - mObjects.rebuildStaticGeometry (); + rebuild = true; } else if (it->first == "Shadows") { mShadows->recreate (); - mObjects.rebuildStaticGeometry (); + rebuild = true; } } @@ -842,6 +847,9 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec if (mWater) mWater->processChangedSettings(settings); + + if (rebuild) + mObjects.rebuildStaticGeometry(); } void RenderingManager::setMenuTransparency(float val) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f2854c879a..433aa8af81 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -430,8 +430,11 @@ void Water::applyRTT() delete mRefraction; mRefraction = NULL; - mRefraction = new Refraction(mCamera); - mRefraction->setHeight(mTop); + if (Settings::Manager::getBool("refraction", "Water")) + { + mRefraction = new Refraction(mCamera); + mRefraction->setHeight(mTop); + } } void Water::applyVisibilityMask() @@ -455,7 +458,8 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin it != settings.end(); ++it) { if ( it->first == "Water" && ( - it->second == "shader" + it->second == "shader" + || it->second == "refraction" || it->second == "rtt size")) applyRT = true; diff --git a/files/materials/core.h b/files/materials/core.h index e498a38090..3385e5face 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -1,9 +1,3 @@ -//#define gammaCorrectRead(v) pow(max(v, 0.00001f), float3(gammaCorrection,gammaCorrection,gammaCorrection)) -//#define gammaCorrectOutput(v) pow(max(v, 0.00001f), float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) - -#define gammaCorrectRead(v) v -#define gammaCorrectOutput(v) v - #if SH_HLSL == 1 || SH_CG == 1 #define shTexture2D sampler2D diff --git a/files/materials/objects.shader b/files/materials/objects.shader index c68705c42e..1e9c4a3343 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -112,8 +112,6 @@ shUniform(float, far) @shAutoConstant(far, far_clip_distance) #endif - //shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) - #if LIGHTING shInput(float3, normalPassthrough) shInput(float3, objSpacePositionPassthrough) @@ -180,7 +178,6 @@ SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV); - shOutputColour(0).xyz = gammaCorrectRead(shOutputColour(0).xyz); #if LIGHTING float3 normal = normalize(normalPassthrough); @@ -271,7 +268,7 @@ // regular fog only if fragment is above water if (worldPos.y > waterLevel || waterEnabled != 1.f) #endif - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); #endif // prevent negative colour output (for example with negative lights) @@ -286,11 +283,11 @@ float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85)) *waterSunGradient * 0.5; + float3 waterSunColour = float3(0.0,1.0,0.85) *waterSunGradient * 0.5; float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = ( gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; + float3 watercolour = ( float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; @@ -303,8 +300,6 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); #endif - shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); - #if MRT shOutputColour(1) = float4(depthPassthrough / far,1,1,1); #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index dfe998210e..9b891e1e80 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -137,8 +137,6 @@ shSampler2D(normalMap) // global normal map - //shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) - @shForeach(@shPropertyString(num_blendmaps)) shSampler2D(blendMap@shIterator) @@ -254,9 +252,9 @@ #if IS_FIRST_PASS == 1 && @shIterator == 0 // first layer of first pass doesn't need a blend map - albedo = gammaCorrectRead(shSample(diffuseMap0, UV * 10).rgb); + albedo = shSample(diffuseMap0, UV * 10).rgb; #else - albedo = shLerp(albedo, gammaCorrectRead(shSample(diffuseMap@shIterator, UV * 10).rgb), blendValues@shPropertyString(blendmap_component_@shIterator)); + albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); #endif @shEndForeach @@ -343,7 +341,7 @@ // regular fog only if fragment is above water if (worldPos.y > waterLevel) #endif - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); #endif // prevent negative colour output (for example with negative lights) @@ -358,12 +356,12 @@ float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85))*waterSunGradient * 0.5; + float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; - float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction + float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; + float3 waterext = float3(0.6, 0.9, 1.0);//water extinction watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; @@ -376,8 +374,6 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); #endif - shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); - #if MRT shOutputColour(1) = float4(depth / far,1,1,1); #endif diff --git a/files/materials/water.mat b/files/materials/water.mat index 2717f26fcb..7546606fc3 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -11,6 +11,9 @@ material Water fragment_program water_fragment cull_hardware none + + scene_blend alpha_blend + depth_write off texture_unit reflectionMap { diff --git a/files/materials/water.shader b/files/materials/water.shader index dbe36a91ce..b02b4761cb 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -62,6 +62,7 @@ // Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) #define RIPPLES 1 +#define REFRACTION @shGlobalSettingBool(refraction) #ifdef SH_VERTEX_SHADER @@ -123,9 +124,9 @@ #define REFR_BUMP 0.12 // refraction distortion amount #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering - #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering + #define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering - #define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction + #define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction #define SPEC_HARDNESS 256 // specular highlights hardness @@ -168,7 +169,9 @@ shUniform(float, far) @shAutoConstant(far, far_clip_distance) shSampler2D(reflectionMap) +#if REFRACTION shSampler2D(refractionMap) +#endif shSampler2D(depthMap) shSampler2D(normalMap) @@ -186,9 +189,6 @@ shUniform(float4, sunPosition) @shAutoConstant(sunPosition, light_position, 0) shUniform(float4, sunSpecular) @shAutoConstant(sunSpecular, light_specular_colour, 0) - - shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) - shUniform(float, renderTargetFlipping) @shAutoConstant(renderTargetFlipping, render_target_flipping) @@ -255,7 +255,7 @@ float s = shSaturate(dot(lR, vVec)*2.0-1.2); float lightScatter = shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); - float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*gammaCorrectRead(float3(1.0,0.4,0.0)), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); + float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*float3(1.0,0.4,0.0), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); // fresnel float ior = (cameraPos.y>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air @@ -264,32 +264,36 @@ fresnel = shSaturate(fresnel); // reflection - float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb); + float3 reflection = shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb; // refraction float3 R = reflect(vVec, normal); - float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(normal.xz*REFR_BUMP))*1.0).rgb); +#if REFRACTION + float3 refraction = shSample(refractionMap, (screenCoords-(normal.xz*REFR_BUMP))*1.0).rgb; // brighten up the refraction underwater refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction; - +#endif // specular float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); +#if REFRACTION shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; - +#else + shOutputColour(0).xyz = reflection + specular * sunSpecular.xyz; +#endif // fog if (isUnderwater == 1) { float waterSunGradient = dot(-vVec, -lVec); waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85))*waterSunGradient * 0.5; + float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; float waterGradient = dot(-vVec, float3(0.0,-1.0,0.0)); waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; - float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction + float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; + float3 waterext = float3(0.6, 0.9, 1.0);//water extinction watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); float darkness = VISIBILITY*2.0; @@ -302,11 +306,14 @@ else { float fogValue = shSaturate((length(cameraPos.xyz-position.xyz) - fogParams.y) * fogParams.w); - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColor), fogValue); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); } - shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); +#if REFRACTION shOutputColour(0).w = 1; +#else + shOutputColour(0).w = shSaturate(fresnel + specular); +#endif } #endif diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index f03305ae75..5b7f106f3b 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -285,6 +285,13 @@ + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 31aa60c42c..044cc34061 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -127,11 +127,10 @@ fog end factor = 1.0 num lights = 8 [Water] -# Enable this to get fancy-looking water with reflections and refractions -# Only available if object shaders are on -# All the settings below have no effect if this is false shader = false +refraction = false + rtt size = 512 reflect terrain = true reflect statics = false @@ -139,7 +138,6 @@ reflect small statics = false reflect actors = false reflect misc = false -# Enable underwater effect. It is not resource intensive, so only disable it if you have problems. underwater effect = false [Sound] From 1c604445ba4f25f4ed2cf92e105e2a57e291bfcf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 06:59:01 -0800 Subject: [PATCH 0241/1483] Store movement vectors as they get returned --- apps/openmw/mwmechanics/actors.cpp | 16 ++++++---------- apps/openmw/mwmechanics/actors.hpp | 7 ++++++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e829d46799..e01303c02c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -258,19 +258,15 @@ namespace MWMechanics if(!paused) { - PtrControllerMap::iterator player(mActors.end()); + mMovement.reserve(mActors.size()); + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - if(iter->first.getRefData().getHandle() == "player") - { - /* Make sure player updates last (in case a cell transition occurs) */ - player = iter; - continue; - } - iter->second.update(duration); + Ogre::Vector3 movement = iter->second.update(duration); + mMovement.push_back(std::make_pair(iter->first, movement)); } - if(player != mActors.end()) - player->second.update(duration); + + mMovement.clear(); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 8c3df6c281..6968f34015 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,9 +25,14 @@ namespace MWMechanics { typedef std::map PtrControllerMap; PtrControllerMap mActors; - float mDuration; + + typedef std::vector > PtrMovementList; + PtrMovementList mMovement; + std::map mDeathCount; + float mDuration; + void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); void adjustMagicEffects (const MWWorld::Ptr& creature); From 499f3ac0d18165cdf0079fa5c711aa390993fd42 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 16:40:41 +0100 Subject: [PATCH 0242/1483] Slightly better ripple normal blending. Not physically accurate at all, but looks good. --- apps/openmw/mwrender/ripplesimulation.cpp | 10 +++++++--- apps/openmw/mwrender/ripplesimulation.hpp | 2 ++ apps/openmw/mwrender/water.cpp | 3 ++- files/materials/water.shader | 7 ++++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 043757e885..249397005b 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -20,7 +20,8 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) mTextureSize(512), mRippleAreaLength(1000), mImpulseSize(20), - mTexelOffset(0,0) + mTexelOffset(0,0), + mFirstUpdate(true) { Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); @@ -106,7 +107,7 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) // try to keep 20 fps mTime += dt; - while (mTime >= 1/20.0) + while (mTime >= 1/20.0 || mFirstUpdate) { mPreviousFrameOffset = mCurrentFrameOffset; @@ -130,7 +131,10 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) heightMapToNormalMap(); swapHeightMaps(); - mTime -= 1/20.0; + if (!mFirstUpdate) + mTime -= 1/20.0; + else + mFirstUpdate = false; } sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 72ff3dbd81..c792a3214e 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -34,6 +34,8 @@ private: float mRippleAreaLength; float mImpulseSize; + bool mFirstUpdate; + Ogre::Camera* mCamera; // own scenemanager to render our simulation diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 433aa8af81..4ff8945ac6 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -401,7 +401,8 @@ void Water::update(float dt, Ogre::Vector3 player) mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - if (player.y <= mTop) + /// \todo player.y is the scene node position (which is above the head) and not the feet position + //if (player.y <= mTop) { mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } diff --git a/files/materials/water.shader b/files/materials/water.shader index b02b4761cb..400fbefb28 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -120,8 +120,8 @@ #define WAVE_SCALE 75 // overall wave scale #define BUMP 1.5 // overall water surface bumpiness - #define REFL_BUMP 0.16 // reflection distortion amount - #define REFR_BUMP 0.12 // refraction distortion amount + #define REFL_BUMP 0.08 // reflection distortion amount + #define REFR_BUMP 0.06 // refraction distortion amount #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering #define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering @@ -232,7 +232,8 @@ float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2 - 1); normal_ripple = normal_ripple.xzy; - normal = normalize(normal + normal_ripple); + //normal = normalize(normal + normal_ripple); + normal = normalize(float3(normal.x + normal_ripple.x, normal.y, normal.z + normal_ripple.z)); // normal for sunlight scattering From 82e4da4e6455249ca402bf886382bd0263e17c8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 07:41:57 -0800 Subject: [PATCH 0243/1483] Get the half-extents from the physicactor --- apps/openmw/mwmechanics/character.cpp | 3 +-- apps/openmw/mwmechanics/movementsolver.cpp | 3 ++- apps/openmw/mwmechanics/movementsolver.hpp | 2 +- libs/openengine/bullet/physic.cpp | 14 ++++++++++++++ libs/openengine/bullet/physic.hpp | 5 +++++ 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b98a863ae2..27c1dc851c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -191,8 +191,7 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * movement; - // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? - Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration, Ogre::Vector3(15,15,30)); + Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); } diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 4a7a59cb31..f17671a61b 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -76,7 +76,7 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) } -Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) { Ogre::Vector3 position(ptr.getRefData().getPosition().pos); @@ -96,6 +96,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = mPhysicActor->getHalfExtents(); Ogre::Vector3 lastNormal(0.0f); Ogre::Vector3 currentNormal(0.0f); diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 450bc055ed..a8b9bf1442 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -25,7 +25,7 @@ namespace MWMechanics MovementSolver(); virtual ~MovementSolver(); - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); private: bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b39ba53a22..7f0f6e2f90 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -156,6 +156,20 @@ namespace Physic } } + Ogre::Vector3 PhysicActor::getHalfExtents() const + { + if(mBody) + { + btBoxShape *box = static_cast(mBody->getCollisionShape()); + if(box != NULL) + { + btVector3 size = box->getHalfExtentsWithMargin(); + return Ogre::Vector3(size.getX(), size.getY(), size.getZ()); + } + } + return Ogre::Vector3(0.0f); + } + void PhysicActor::runPmove(){ Pmove(pmove); Ogre::Vector3 newpos = pmove->ps.origin; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 76bdb491d9..d98625c0ae 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -117,6 +117,11 @@ namespace Physic */ void setScale(float scale); + /** + * Returns the half extents for this PhysiActor + */ + Ogre::Vector3 getHalfExtents() const; + /** * Runs pmove for this PhysicActor */ From a782a9109b131c04da01a0052afcbf8d7c208d97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:24:22 -0800 Subject: [PATCH 0244/1483] Store the vertical velocity in the physic actor --- apps/openmw/mwmechanics/movementsolver.cpp | 3 ++- apps/openmw/mwmechanics/movementsolver.hpp | 2 -- libs/openengine/bullet/physic.cpp | 13 ++++++++++++- libs/openengine/bullet/physic.hpp | 11 +++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index f17671a61b..3fddb28fe0 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -15,7 +15,6 @@ namespace MWMechanics MovementSolver::MovementSolver() : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) - , verticalVelocity(0.0f) { } @@ -89,6 +88,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. float maxslope=45; + float verticalVelocity = mPhysicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); @@ -156,6 +156,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 verticalVelocity = clippedVelocity.z; verticalVelocity -= time*400; + mPhysicActor->setVerticalForce(verticalVelocity); return newPosition; } diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index a8b9bf1442..6a965b56ac 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -37,8 +37,6 @@ namespace MWMechanics OEngine::Physic::PhysicEngine *mEngine; OEngine::Physic::PhysicActor *mPhysicActor; - - float verticalVelocity; }; } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7f0f6e2f90..1ae916f81c 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -28,7 +28,7 @@ namespace Physic }; PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0) + mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -170,6 +170,17 @@ namespace Physic return Ogre::Vector3(0.0f); } + void PhysicActor::setVerticalForce(float force) + { + verticalForce = force; + } + + float PhysicActor::getVerticalForce() const + { + return verticalForce; + } + + void PhysicActor::runPmove(){ Pmove(pmove); Ogre::Vector3 newpos = pmove->ps.origin; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index d98625c0ae..daf1c09f2b 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -122,6 +122,16 @@ namespace Physic */ Ogre::Vector3 getHalfExtents() const; + /** + * Sets the current amount of vertical force (gravity) affecting this physic actor + */ + void setVerticalForce(float force); + + /** + * Gets the current amount of vertical force (gravity) affecting this physic actor + */ + float getVerticalForce() const; + /** * Runs pmove for this PhysicActor */ @@ -141,6 +151,7 @@ namespace Physic Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; + float verticalForce; bool collisionMode; std::string mMesh; PhysicEngine* mEngine; From d50832081cddc2f1238d41de85c62657ace1f3f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:37:02 -0800 Subject: [PATCH 0245/1483] Remove the unneeded PhysicActor field from MovementSolver --- apps/openmw/mwmechanics/movementsolver.cpp | 24 +++++++++++----------- apps/openmw/mwmechanics/movementsolver.hpp | 2 -- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 3fddb28fe0..544cb2ab88 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -13,6 +13,8 @@ namespace MWMechanics { +static const float sMaxSlope = 45.0f; + MovementSolver::MovementSolver() : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) { @@ -49,17 +51,16 @@ void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) { - static const float maxslope = 45.0f; traceResults trace; // no initialization needed newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > maxslope)) + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); - if(getSlope(trace.planenormal) < maxslope) + if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. position = trace.endpos; @@ -80,23 +81,22 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 Ogre::Vector3 position(ptr.getRefData().getPosition().pos); /* Anything to collide with? */ - mPhysicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); - if(!mPhysicActor || !mPhysicActor->getCollisionMode()) + OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); + if(!physicActor || !physicActor->getCollisionMode()) return position + movement; traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - float maxslope=45; - float verticalVelocity = mPhysicActor->getVerticalForce(); + float verticalVelocity = physicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); - Ogre::Vector3 halfExtents = mPhysicActor->getHalfExtents(); + float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); Ogre::Vector3 lastNormal(0.0f); Ogre::Vector3 currentNormal(0.0f); @@ -106,7 +106,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); if(trace.fraction < 1.0f) { - if(getSlope(trace.planenormal) > maxslope) + if(getSlope(trace.planenormal) > sMaxSlope) { // if we're on a really steep slope, don't listen to user input clippedVelocity.x = clippedVelocity.y = 0.0f; @@ -129,7 +129,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 if(trace.fraction != 1.0f) { //std::cout<<"angle: "< maxslope || currentNormal == lastNormal) + if(getSlope(currentNormal) > sMaxSlope || currentNormal == lastNormal) { if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) std::cout<< "stepped" <setVerticalForce(verticalVelocity); + physicActor->setVerticalForce(verticalVelocity); return newPosition; } diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 6a965b56ac..1c56df0364 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -13,7 +13,6 @@ namespace OEngine namespace Physic { class PhysicEngine; - class PhysicActor; } } @@ -36,7 +35,6 @@ namespace MWMechanics float getSlope(const Ogre::Vector3 &normal); OEngine::Physic::PhysicEngine *mEngine; - OEngine::Physic::PhysicActor *mPhysicActor; }; } From 3251796ba04b513881658f693b14b7762d11ae77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:57:08 -0800 Subject: [PATCH 0246/1483] Fix left/right movement --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8be..991cf4f518 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -271,12 +271,12 @@ namespace MWInput if (actionIsActive(A_MoveLeft)) { mPlayer.setAutoMove (false); - mPlayer.setLeftRight (1); + mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { mPlayer.setAutoMove (false); - mPlayer.setLeftRight (-1); + mPlayer.setLeftRight (1); } else mPlayer.setLeftRight (0); From c4d518132f83cb0697361fa98e69e3b1bd6a8b88 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 19:22:08 +0100 Subject: [PATCH 0247/1483] With the 1x1 background window trick, we can apply VSync without restart. Some issues left though. --- apps/openmw/mwbase/inputmanager.hpp | 3 +++ apps/openmw/mwgui/settingswindow.cpp | 8 ++----- apps/openmw/mwinput/inputmanagerimp.cpp | 28 ++++++++++++++++++---- apps/openmw/mwinput/inputmanagerimp.hpp | 8 +++++++ apps/openmw/mwrender/renderingmanager.cpp | 29 ++++++++++++++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 2 ++ libs/openengine/ogre/renderer.cpp | 25 +++++++++++++++---- libs/openengine/ogre/renderer.hpp | 3 +++ 8 files changed, 90 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 8293cbfa7e..f69e1a1529 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -39,6 +39,9 @@ namespace MWBase virtual int getNumActions() = 0; virtual void enableDetectingBindingMode (int action) = 0; virtual void resetToDefaultBindings() = 0; + + virtual void create () = 0; + virtual void destroy () = 0; }; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 343c96cece..75fc2b7a21 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -370,14 +370,10 @@ namespace MWGui apply(); } } - else if (_sender == mVSyncButton) - { - Settings::Manager::setBool("vsync", "Video", newState); - MWBase::Environment::get().getWindowManager()-> - messageBox("VSync will be applied after a restart", std::vector()); - } else { + if (_sender == mVSyncButton) + Settings::Manager::setBool("vsync", "Video", newState); if (_sender == mWaterShaderButton) Settings::Manager::setBool("shader", "Water", newState); else if (_sender == mRefractionButton) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8be..95d221933e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -41,9 +41,11 @@ namespace MWInput , mMouseX(ogre.getWindow()->getWidth ()/2.f) , mMouseY(ogre.getWindow()->getHeight ()/2.f) , mMouseWheel(0) - , mUserFile(userFile) , mDragDrop(false) , mGuiCursorEnabled(false) + , mDebug(debug) + , mUserFile(userFile) + , mUserFileExists(userFileExists) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) @@ -51,8 +53,15 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) + , mCreated(false) { - Ogre::RenderWindow* window = ogre.getWindow (); + create(); + } + + + void InputManager::create() + { + Ogre::RenderWindow* window = mOgre.getWindow (); size_t windowHnd; resetIdleTime(); @@ -67,7 +76,7 @@ namespace MWInput // Set non-exclusive mouse and keyboard input if the user requested // it. - if (debug) + if (mDebug) { #if defined OIS_WIN32_PLATFORM pl.insert(std::make_pair(std::string("w32_mouse"), @@ -112,7 +121,7 @@ namespace MWInput MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mMouse->getMouseState ().Z.abs); - std::string file = userFileExists ? userFile : ""; + std::string file = mUserFileExists ? mUserFile : ""; mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); loadKeyDefaults(); @@ -131,9 +140,11 @@ namespace MWInput mControlSwitch["vanitymode"] = true; changeInputMode(false); + + mCreated = true; } - InputManager::~InputManager() + void InputManager::destroy() { mInputCtrl->save (mUserFile); @@ -142,6 +153,12 @@ namespace MWInput mInputManager->destroyInputObject(mKeyboard); mInputManager->destroyInputObject(mMouse); OIS::InputManager::destroyInputSystem(mInputManager); + mCreated = false; + } + + InputManager::~InputManager() + { + destroy(); } void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) @@ -239,6 +256,7 @@ namespace MWInput void InputManager::update(float dt, bool loading) { + if (!mCreated) return; // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f285..100bba4fb7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -131,6 +131,8 @@ namespace MWInput std::string mUserFile; + bool mCreated; + bool mDragDrop; bool mInvertY; @@ -148,9 +150,15 @@ namespace MWInput float mMouseX; float mMouseY; int mMouseWheel; + bool mDebug; + bool mUserFileExists; std::map mControlSwitch; + public: + virtual void create(); + virtual void destroy(); + private: void adjustMouseRegion(int width, int height); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 69f3914e59..9e50b2bced 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -46,7 +46,8 @@ namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) - : mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0), mPhysicsEngine(engine) + : mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0), mPhysicsEngine(engine), + mRecreateWindowInNextFrame(false) { // select best shader mode bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); @@ -323,6 +324,22 @@ RenderingManager::moveObjectToCell( void RenderingManager::update (float duration, bool paused) { + if (mRecreateWindowInNextFrame) + { + MWBase::Environment::get().getInputManager()->destroy(); + + OEngine::Render::WindowSettings windowSettings; + windowSettings.fullscreen = Settings::Manager::getBool("fullscreen", "Video"); + windowSettings.window_x = Settings::Manager::getInt("resolution x", "Video"); + windowSettings.window_y = Settings::Manager::getInt("resolution y", "Video"); + windowSettings.vsync = Settings::Manager::getBool("vsync", "Video"); + std::string aa = Settings::Manager::getString("antialiasing", "Video"); + windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + mRendering.recreateWindow("OpenMW", windowSettings); + + MWBase::Environment::get().getInputManager()->create(); + mRecreateWindowInNextFrame = false; + } Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -756,6 +773,7 @@ Compositors* RenderingManager::getCompositors() void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) { bool changeRes = false; + bool recreateWindow = false; bool rebuild = false; // rebuild static geometry (necessary after any material changes) for (Settings::CategorySettingVector::const_iterator it=settings.begin(); it != settings.end(); ++it) @@ -774,6 +792,8 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec || it->second == "resolution y" || it->second == "fullscreen")) changeRes = true; + else if (it->first == "Video" && it->second == "vsync") + recreateWindow = true; else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); else if ((it->second == "texture filtering" && it->first == "General") @@ -845,6 +865,13 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } + if (recreateWindow) + { + mRecreateWindowInNextFrame = true; + // We can not do this now, because this might get triggered from the input listener + // and destroying/recreating the input system at that point would cause a crash + } + if (mWater) mWater->processChangedSettings(settings); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 71ac742c2a..670f3dc85e 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -260,6 +260,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList MWRender::Compositors* mCompositors; VideoPlayer* mVideoPlayer; + + bool mRecreateWindowInNextFrame; }; } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 039aba2264..e0abf420ea 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -205,13 +205,31 @@ void OgreRenderer::configure(const std::string &logPath, rs->setConfigOption ("RTT Preferred Mode", rttMode); } +void OgreRenderer::recreateWindow(const std::string &title, const WindowSettings &settings) +{ + Ogre::ColourValue viewportBG = mView->getBackgroundColour(); + + mRoot->destroyRenderTarget(mWindow); + NameValuePairList params; + params.insert(std::make_pair("title", title)); + params.insert(std::make_pair("FSAA", settings.fsaa)); + params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); + + mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); + + // Create one viewport, entire window + mView = mWindow->addViewport(mCamera); + mView->setBackgroundColour(viewportBG); + + adjustViewport(); +} + void OgreRenderer::createWindow(const std::string &title, const WindowSettings& settings) { assert(mRoot); mRoot->initialise(false); // create a hidden 1x1 background window to keep resources when recreating the secondary (real) window - /* NameValuePairList params_; params_.insert(std::make_pair("title", title)); params_.insert(std::make_pair("FSAA", "0")); @@ -219,7 +237,6 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& params_.insert(std::make_pair("hidden", "true")); Ogre::RenderWindow* hiddenWindow = mRoot->createRenderWindow("InactiveHidden", 1, 1, false, ¶ms_); hiddenWindow->setActive(false); - */ NameValuePairList params; params.insert(std::make_pair("title", title)); @@ -271,12 +288,12 @@ void OgreRenderer::adjustViewport() void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) { - Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); + //Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); } void OgreRenderer::removeWindowEventListener(Ogre::WindowEventListener* listener) { - Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); + //Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); } void OgreRenderer::setFov(float fov) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index a8788dfcaf..251dc9c54d 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -66,6 +66,7 @@ namespace OEngine #endif class Fader; + class OgreRenderer { #if defined(__APPLE__) && !defined(__LP64__) @@ -138,6 +139,8 @@ namespace OEngine /// Create a window with the given title void createWindow(const std::string &title, const WindowSettings& settings); + void recreateWindow (const std::string &title, const WindowSettings& settings); + /// Set up the scene manager, camera and viewport void createScene(const std::string& camName="Camera",// Camera name float fov=55, // Field of view angle From 2cdda967980acf429ab05d64358c8100e5813795 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 10:23:26 -0800 Subject: [PATCH 0248/1483] Clear out some unneeded doPhysics stuff --- apps/openmw/mwworld/physicssystem.cpp | 58 --------------------------- apps/openmw/mwworld/physicssystem.hpp | 3 -- apps/openmw/mwworld/worldimp.cpp | 43 -------------------- 3 files changed, 104 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9e2e94143f..7d77718a3c 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -190,66 +190,8 @@ namespace MWWorld //set the DebugRenderingMode. To disable it,set it to 0 //eng->setDebugRenderingMode(1); - //set the movement keys to 0 (no movement) for every actor) - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - OEngine::Physic::PhysicActor* act = it->second; - act->setMovement(0,0,0); - } - - playerMove::playercmd& pm_ref = playerphysics->cmd; - - - pm_ref.rightmove = 0; - pm_ref.forwardmove = 0; - pm_ref.upmove = 0; - - - //playerphysics->ps.move_type = PM_NOCLIP; - for (std::vector >::const_iterator iter (actors.begin()); - iter!=actors.end(); ++iter) - { - //dirty stuff to get the camera orientation. Must be changed! - if (iter->first == "player") { - playerphysics->ps.viewangles.x = - Ogre::Radian(mPlayerData.pitch).valueDegrees(); - - - - playerphysics->ps.viewangles.y = - Ogre::Radian(mPlayerData.yaw).valueDegrees() + 90; - - pm_ref.rightmove = iter->second.x; - pm_ref.forwardmove = -iter->second.y; - pm_ref.upmove = iter->second.z; - } - } - mEngine->stepSimulation(dt); } - std::vector< std::pair > PhysicsSystem::doPhysicsFixed ( - const std::vector >& actors) - { - Pmove(playerphysics); - - - std::vector< std::pair > response; - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - - Ogre::Vector3 coord = it->second->getPosition(); - if(it->first == "player"){ - - coord = playerphysics->ps.origin ; - - } - - - response.push_back(std::pair(it->first, coord)); - } - - return response; - } void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 81715c31e9..b28f651f67 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -17,9 +17,6 @@ namespace MWWorld void doPhysics(float duration, const std::vector >& actors); ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - std::vector< std::pair > doPhysicsFixed (const std::vector >& actors); - ///< do physics with fixed timestep - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - void addObject (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 246467fb0e..5f6a2f4a71 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -838,49 +838,6 @@ namespace MWWorld float duration) { mPhysics->doPhysics(duration, actors); - - const int tick = 16; // 16 ms ^= 60 Hz - - // Game clock part of the loop, contains everything that has to be executed in a fixed timestep - long long dt = mTimer.getMilliseconds() - lastTick; - if (dt >= 100) - { - // throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps - lastTick += (dt - 100); - dt = 100; - } - while (dt >= tick) - { - dt -= tick; - lastTick += tick; - - std::vector< std::pair > vectors = mPhysics->doPhysicsFixed (actors); - - std::vector< std::pair >::iterator player = vectors.end(); - - for (std::vector< std::pair >::iterator it = vectors.begin(); - it!= vectors.end(); ++it) - { - if (it->first=="player") - { - player = it; - } - else - { - MWWorld::Ptr ptr = getPtrViaHandle (it->first); - moveObjectImp (ptr, it->second.x, it->second.y, it->second.z); - } - } - - // Make sure player is moved last (otherwise the cell might change in the middle of an update - // loop) - if (player!=vectors.end()) - { - if (moveObjectImp (getPtrViaHandle (player->first), - player->second.x, player->second.y, player->second.z) == true) - return; // abort the current loop if the cell has changed - } - } } bool World::toggleCollisionMode() From 0a4568bd11cf6d6a7e9f4f7cbd3e96d7d691faae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 11:03:39 -0800 Subject: [PATCH 0249/1483] Move the PtrMovementList typedef to MWWorld Use it for the doPhysics parameter, too --- apps/openmw/mwbase/world.hpp | 5 +++-- apps/openmw/mwmechanics/actors.hpp | 4 ++-- apps/openmw/mwworld/physicssystem.cpp | 7 ------- apps/openmw/mwworld/physicssystem.hpp | 3 --- apps/openmw/mwworld/worldimp.cpp | 4 +--- apps/openmw/mwworld/worldimp.hpp | 3 +-- 6 files changed, 7 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5f6e27867d..b5d8aec9cc 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -52,6 +52,8 @@ namespace MWWorld class TimeStamp; class ESMStore; class RefData; + + typedef std::vector > PtrMovementList; } namespace MWBase @@ -233,8 +235,7 @@ namespace MWBase virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0; ///< Convert position to cell numbers - virtual void doPhysics (const std::vector >& actors, - float duration) = 0; + virtual void doPhysics (const MWWorld::PtrMovementList &actors, float duration) = 0; ///< Run physics simulation and modify \a world accordingly. virtual bool toggleCollisionMode() = 0; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6968f34015..fbd787e835 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -7,6 +7,7 @@ #include #include "character.hpp" +#include "../mwbase/world.hpp" namespace Ogre { @@ -26,8 +27,7 @@ namespace MWMechanics typedef std::map PtrControllerMap; PtrControllerMap mActors; - typedef std::vector > PtrMovementList; - PtrMovementList mMovement; + MWWorld::PtrMovementList mMovement; std::map mDeathCount; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7d77718a3c..c95abc5a0f 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -185,13 +185,6 @@ namespace MWWorld } } - void PhysicsSystem::doPhysics(float dt, const std::vector >& actors) - { - //set the DebugRenderingMode. To disable it,set it to 0 - //eng->setDebugRenderingMode(1); - - } - void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index b28f651f67..06b29d2901 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -14,9 +14,6 @@ namespace MWWorld PhysicsSystem (OEngine::Render::OgreRenderer &_rend); ~PhysicsSystem (); - void doPhysics(float duration, const std::vector >& actors); - ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - void addObject (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5f6a2f4a71..d900f555c9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -834,10 +834,8 @@ namespace MWWorld --cellY; } - void World::doPhysics (const std::vector >& actors, - float duration) + void World::doPhysics(const PtrMovementList &actors, float duration) { - mPhysics->doPhysics(duration, actors); } bool World::toggleCollisionMode() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 062387e922..5977664695 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -263,8 +263,7 @@ namespace MWWorld virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; ///< Convert position to cell numbers - virtual void doPhysics (const std::vector >& actors, - float duration); + virtual void doPhysics(const PtrMovementList &actors, float duration); ///< Run physics simulation and modify \a world accordingly. virtual bool toggleCollisionMode(); From 31f760cccec9a1bab571181e38699f8357b8b285 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 20:26:13 +0100 Subject: [PATCH 0250/1483] Fixing issues from last commit: restored input and occlusion queries --- apps/openmw/mwinput/inputmanagerimp.cpp | 11 +++-------- apps/openmw/mwinput/inputmanagerimp.hpp | 2 -- apps/openmw/mwrender/occlusionquery.cpp | 13 ++++++++++++- apps/openmw/mwrender/occlusionquery.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 13 ++++++++++++- apps/openmw/mwrender/water.cpp | 2 +- libs/openengine/ogre/renderer.cpp | 4 ++-- 7 files changed, 30 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 95d221933e..00849503c6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -53,9 +53,10 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) - , mCreated(false) { create(); + + changeInputMode(false); } @@ -138,10 +139,6 @@ namespace MWInput mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; - - changeInputMode(false); - - mCreated = true; } void InputManager::destroy() @@ -153,7 +150,6 @@ namespace MWInput mInputManager->destroyInputObject(mKeyboard); mInputManager->destroyInputObject(mMouse); OIS::InputManager::destroyInputSystem(mInputManager); - mCreated = false; } InputManager::~InputManager() @@ -250,13 +246,12 @@ namespace MWInput case A_ToggleHUD: mWindows.toggleHud(); break; - } + } } } void InputManager::update(float dt, bool loading) { - if (!mCreated) return; // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 100bba4fb7..7be35ee0b6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -131,8 +131,6 @@ namespace MWInput std::string mUserFile; - bool mCreated; - bool mDragDrop; bool mInvertY; diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index c9e649fe6f..8d16d7b7d5 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -15,7 +15,7 @@ using namespace Ogre; OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0), mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), - mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false), + mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mBBNode(0), mActive(false) { mRendering = renderer; @@ -94,6 +94,9 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod OcclusionQuery::~OcclusionQuery() { + mRendering->getScene()->removeRenderObjectListener (this); + mRendering->getScene()->removeRenderQueueListener(this); + RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); if (mSunTotalAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); if (mSunVisibleAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); @@ -109,6 +112,7 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass const LightList* pLightList, bool suppressRenderStateChanges) { if (!mActive) return; + // The following code activates and deactivates the occlusion queries // so that the queries only include the rendering of the intended meshes @@ -116,6 +120,7 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass // Each occlusion query should only last a single rendering if (mActiveQuery != NULL) { + std::cout << "ending query (notifyRenderSingleObject)" << std::endl; mActiveQuery->endOcclusionQuery(); mActiveQuery = NULL; } @@ -123,6 +128,7 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass // Open a new occlusion query if (mDoQuery == true) { + std::cout << "opening new query" << std::endl; if (rend == mBBQueryTotal) { mActiveQuery = mSunTotalAreaQuery; @@ -208,6 +214,7 @@ void OcclusionQuery::update(float duration) && !mSunVisibleAreaQuery->isStillOutstanding() && !mSingleObjectQuery->isStillOutstanding()) { + std::cout << "update(), nothing is outstanding"<< std::endl; unsigned int totalPixels; unsigned int visiblePixels; @@ -243,6 +250,8 @@ void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNod assert( !occlusionTestPending() && "Occlusion test still pending"); + std::cout << "Occlusion test called " << std::endl; + mBBQuerySingleObject->setVisible(true); mObjectNode->setPosition(position); @@ -250,6 +259,8 @@ void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNod mObjectNode->setScale( Vector3(1,1,1)*(position - mRendering->getCamera()->getRealPosition()).length() ); mQuerySingleObjectRequested = true; + + mDoQuery = true; } bool OcclusionQuery::occlusionTestPending() diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index af6f668c17..c7a5757d3c 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -95,7 +95,6 @@ namespace MWRender bool mSupported; bool mDoQuery; - bool mDoQuery2; bool mQuerySingleObjectRequested; bool mQuerySingleObjectStarted; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9e50b2bced..afbdbb06f3 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -326,6 +326,10 @@ void RenderingManager::update (float duration, bool paused) { if (mRecreateWindowInNextFrame) { + mRecreateWindowInNextFrame = false; + + mRendering.removeWindowEventListener(this); + mRendering.getWindow()->removeListener(this); MWBase::Environment::get().getInputManager()->destroy(); OEngine::Render::WindowSettings windowSettings; @@ -338,8 +342,15 @@ void RenderingManager::update (float duration, bool paused) mRendering.recreateWindow("OpenMW", windowSettings); MWBase::Environment::get().getInputManager()->create(); - mRecreateWindowInNextFrame = false; + mRendering.setWindowEventListener (this); + mRendering.getWindow()->addListener(this); + + // this is necessary, otherwise it would just endlessly wait for the last query and it would never return + delete mOcclusionQuery; + mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); } + + Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 4ff8945ac6..8678295649 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -418,7 +418,7 @@ void Water::applyRTT() mReflection = NULL; // Create rendertarget for reflection - int rttsize = Settings::Manager::getInt("rtt size", "Water"); + //int rttsize = Settings::Manager::getInt("rtt size", "Water"); if (Settings::Manager::getBool("shader", "Water")) { diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index e0abf420ea..c4f35e0872 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -288,12 +288,12 @@ void OgreRenderer::adjustViewport() void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) { - //Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); } void OgreRenderer::removeWindowEventListener(Ogre::WindowEventListener* listener) { - //Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); } void OgreRenderer::setFov(float fov) From 608c112f34461760264240ded5f5140d2a24c7c2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 20:48:25 +0100 Subject: [PATCH 0251/1483] Supply the new render window to mygui --- apps/openmw/mwgui/loadingscreen.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++++++++++++--- apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwrender/occlusionquery.cpp | 5 ----- libs/openengine/gui/manager.cpp | 6 ++++++ libs/openengine/gui/manager.hpp | 2 ++ 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index c14087a3b9..24b3850710 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -19,6 +19,8 @@ namespace MWGui void onResChange(int w, int h); + void updateWindow(Ogre::RenderWindow* rw) { mWindow = rw; } + private: bool mFirstLoad; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a1f915ac9b..3ae0f37c58 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -56,10 +56,11 @@ using namespace MWGui; WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, + const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage) : mGuiManager(NULL) + , mRendering(ogre) , mHud(NULL) , mMap(NULL) , mMenu(NULL) @@ -111,7 +112,7 @@ WindowManager::WindowManager( { // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); + mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); mGui = mGuiManager->getGui(); //Register own widgets with MyGUI @@ -172,7 +173,7 @@ WindowManager::WindowManager( mEnchantingDialog = new EnchantingDialog(*this); mTrainingWindow = new TrainingWindow(*this); - mLoadingScreen = new LoadingScreen(mOgre->getScene (), mOgre->getWindow (), *this); + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); @@ -763,6 +764,7 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); bool changeRes = false; + bool windowRecreated = false; for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { @@ -772,6 +774,8 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector { changeRes = true; } + else if (it->first == "Video" && it->second == "vsync") + windowRecreated = true; else if (it->first == "HUD" && it->second == "crosshair") mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); else if (it->first == "GUI" && it->second == "subtitles") @@ -795,6 +799,11 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); mInputBlocker->setSize(MyGUI::IntSize(x,y)); } + if (windowRecreated) + { + mGuiManager->updateWindow (mRendering->getWindow ()); + mLoadingScreen->updateWindow (mRendering->getWindow ()); + } } void WindowManager::pushGuiMode(GuiMode mode) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8bcb88e224..bae1956699 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -229,6 +229,7 @@ namespace MWGui private: OEngine::GUI::MyGUIManager *mGuiManager; + OEngine::Render::OgreRenderer *mRendering; HUD *mHud; MapWindow *mMap; MainMenu *mMenu; diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 8d16d7b7d5..81a3f43274 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -120,7 +120,6 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass // Each occlusion query should only last a single rendering if (mActiveQuery != NULL) { - std::cout << "ending query (notifyRenderSingleObject)" << std::endl; mActiveQuery->endOcclusionQuery(); mActiveQuery = NULL; } @@ -128,7 +127,6 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass // Open a new occlusion query if (mDoQuery == true) { - std::cout << "opening new query" << std::endl; if (rend == mBBQueryTotal) { mActiveQuery = mSunTotalAreaQuery; @@ -214,7 +212,6 @@ void OcclusionQuery::update(float duration) && !mSunVisibleAreaQuery->isStillOutstanding() && !mSingleObjectQuery->isStillOutstanding()) { - std::cout << "update(), nothing is outstanding"<< std::endl; unsigned int totalPixels; unsigned int visiblePixels; @@ -250,8 +247,6 @@ void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNod assert( !occlusionTestPending() && "Occlusion test still pending"); - std::cout << "Occlusion test called " << std::endl; - mBBQuerySingleObject->setVisible(true); mObjectNode->setPosition(position); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 925891e1b3..9cc2bf3815 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -56,6 +56,12 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool mGui->initialise("core.xml"); } +void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) +{ + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); +} + void MyGUIManager::shutdown() { mGui->shutdown (); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index c0f98da88b..39948a8290 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -38,6 +38,8 @@ namespace GUI shutdown(); } + void updateWindow (Ogre::RenderWindow* wnd); + void setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")); void shutdown(); From 2c39760bd50284a809ba9fc091d01929e23eb3f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 12:45:10 -0800 Subject: [PATCH 0252/1483] Move the movement solver code to mwworld's physics system --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/character.cpp | 26 +--- apps/openmw/mwmechanics/character.hpp | 4 - apps/openmw/mwmechanics/movementsolver.cpp | 164 --------------------- apps/openmw/mwmechanics/movementsolver.hpp | 41 ------ apps/openmw/mwworld/physicssystem.cpp | 152 +++++++++++++++++++ apps/openmw/mwworld/physicssystem.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 21 +++ 9 files changed, 184 insertions(+), 229 deletions(-) delete mode 100644 apps/openmw/mwmechanics/movementsolver.cpp delete mode 100644 apps/openmw/mwmechanics/movementsolver.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 184a00d509..a491ea5ce0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate movementsolver + aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e01303c02c..a8c05f17e3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -265,6 +265,7 @@ namespace MWMechanics Ogre::Vector3 movement = iter->second.update(duration); mMovement.push_back(std::make_pair(iter->first, movement)); } + MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration); mMovement.clear(); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 27c1dc851c..3899b05ab7 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,8 +29,6 @@ #include "../mwworld/class.hpp" -#include "movementsolver.hpp" - namespace MWMechanics { @@ -79,7 +77,6 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { - mMovementSolver = new MovementSolver(); if(!mAnimation) return; @@ -98,7 +95,6 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { - mMovementSolver = new MovementSolver(); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ @@ -107,7 +103,6 @@ CharacterController::CharacterController(const CharacterController &rhs) CharacterController::~CharacterController() { - delete mMovementSolver; } @@ -181,21 +176,14 @@ Ogre::Vector3 CharacterController::update(float duration) } mSkipAnim = false; - if(duration > 0.0f) - { - const ESM::Position &refpos = mPtr.getRefData().getPosition(); + const ESM::Position &refpos = mPtr.getRefData().getPosition(); + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - - Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration); - MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); - } - - return Ogre::Vector3(0.0f); + return movement; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index efd90ca196..adb6364a0c 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -13,8 +13,6 @@ namespace MWRender namespace MWMechanics { -class MovementSolver; - enum CharacterState { CharState_Idle, CharState_Idle2, @@ -51,8 +49,6 @@ class CharacterController CharacterState mState; bool mSkipAnim; - MovementSolver *mMovementSolver; - protected: /* Called by the animation whenever a new text key is reached. */ void markerEvent(float time, const std::string &evt); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp deleted file mode 100644 index 544cb2ab88..0000000000 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "movementsolver.hpp" - -#include "libs/openengine/bullet/trace.h" -#include "libs/openengine/bullet/physic.hpp" - -#include "../mwworld/ptr.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -#include - - -namespace MWMechanics -{ - -static const float sMaxSlope = 45.0f; - -MovementSolver::MovementSolver() - : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) -{ -} - -MovementSolver::~MovementSolver() -{ - // nothing to do -} - -void MovementSolver::clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) -{ - //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. - //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. - float backoff; - - backoff = in.dotProduct(normal); - if(backoff < 0.0f) - backoff *= overbounce; - else - backoff /= overbounce; - - out = in - (normal*backoff); -} - -void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) -{ - Ogre::Vector3 normalizedDirection(direction); - normalizedDirection.normalise(); - - // no divide by normalizedDirection.length necessary because it's normalized - velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); -} - -bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) -{ - traceResults trace; // no initialization needed - - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), - position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, - halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) - return false; - - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); - if(getSlope(trace.planenormal) < sMaxSlope) - { - // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. - position = trace.endpos; - return true; - } - - return false; -} - -float MovementSolver::getSlope(const Ogre::Vector3 &normal) -{ - return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); -} - - -Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) -{ - Ogre::Vector3 position(ptr.getRefData().getPosition().pos); - - /* Anything to collide with? */ - OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); - if(!physicActor || !physicActor->getCollisionMode()) - return position + movement; - - traceResults trace; //no initialization needed - int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - - float verticalVelocity = physicActor->getVerticalForce(); - Ogre::Vector3 horizontalVelocity = movement/time; - Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps - Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); - - float remainingTime = time; - bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); - Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); - - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); - Ogre::Vector3 newPosition = position; - - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction < 1.0f) - { - if(getSlope(trace.planenormal) > sMaxSlope) - { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); - } - } - - do { - // trace to where character would go if there were no obstructions - newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); - newPosition = trace.endpos; - currentNormal = trace.planenormal; - remainingTime = remainingTime * (1.0f-trace.fraction); - - // check for obstructions - if(trace.fraction != 1.0f) - { - //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) - { - if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) - std::cout<< "stepped" <setVerticalForce(verticalVelocity); - - return newPosition; -} - -} diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp deleted file mode 100644 index 1c56df0364..0000000000 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef GAME_MWMECHANICS_MOVEMENTSOLVER_H -#define GAME_MWMECHANICS_MOVEMENTSOLVER_H - -#include - -namespace MWWorld -{ - class Ptr; -} - -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - -namespace MWMechanics -{ - class MovementSolver - { - public: - MovementSolver(); - virtual ~MovementSolver(); - - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); - - private: - bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); - - void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce); - void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction); - - float getSlope(const Ogre::Vector3 &normal); - - OEngine::Physic::PhysicEngine *mEngine; - }; -} - -#endif /* GAME_MWMECHANICS_MOVEMENTSOLVER_H */ diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c95abc5a0f..2d83c9a040 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -21,6 +21,153 @@ using namespace Ogre; namespace MWWorld { + static const float sMaxSlope = 45.0f; + + class MovementSolver + { + private: + static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, + float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior, + OEngine::Physic::PhysicEngine *engine) + { + traceResults trace; // no initialization needed + + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), + position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) + return false; + + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, engine); + if(getSlope(trace.planenormal) < sMaxSlope) + { + // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. + position = trace.endpos; + return true; + } + + return false; + } + + static void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, + const float overbounce) + { + //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. + //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. + float backoff; + + backoff = in.dotProduct(normal); + if(backoff < 0.0f) + backoff *= overbounce; + else + backoff /= overbounce; + + out = in - (normal*backoff); + } + + static void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) + { + Ogre::Vector3 normalizedDirection(direction); + normalizedDirection.normalise(); + + // no divide by normalizedDirection.length necessary because it's normalized + velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); + } + + static float getSlope(const Ogre::Vector3 &normal) + { + return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); + } + + public: + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, + OEngine::Physic::PhysicEngine *engine) + { + Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + + /* Anything to collide with? */ + OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); + if(!physicActor || !physicActor->getCollisionMode()) + return position + movement; + + traceResults trace; //no initialization needed + int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + + float verticalVelocity = physicActor->getVerticalForce(); + Ogre::Vector3 horizontalVelocity = movement/time; + Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); + + float remainingTime = time; + bool isInterior = !ptr.getCell()->isExterior(); + float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); + + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f) + { + if(getSlope(trace.planenormal) > sMaxSlope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } + } + + do { + // trace to where character would go if there were no obstructions + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); + newPosition = trace.endpos; + currentNormal = trace.planenormal; + remainingTime = remainingTime * (1.0f-trace.fraction); + + // check for obstructions + if(trace.fraction != 1.0f) + { + //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + { + if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + std::cout<< "stepped" <setVerticalForce(verticalVelocity); + + return newPosition; + } + }; + + PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { @@ -185,6 +332,11 @@ namespace MWWorld } } + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) + { + return MovementSolver::move(ptr, movement, time, mEngine); + } + void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 06b29d2901..d897c78e9e 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -35,6 +35,8 @@ namespace MWWorld bool toggleCollisionMode(); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); + std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d900f555c9..fb31c54ab2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -836,6 +836,27 @@ namespace MWWorld void World::doPhysics(const PtrMovementList &actors, float duration) { + /* No duration? Shouldn't be any movement, then. */ + if(duration <= 0.0f) + return; + + PtrMovementList::const_iterator player(actors.end()); + for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++) + { + if(iter->first.getRefData().getHandle() == "player") + { + /* Handle player last, in case a cell transition occurs */ + player = iter; + continue; + } + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration); + moveObjectImp(iter->first, vec.x, vec.y, vec.z); + } + if(player != actors.end()) + { + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration); + moveObjectImp(player->first, vec.x, vec.y, vec.z); + } } bool World::toggleCollisionMode() From f7f1adfb9d6265d95804c3df2793e47aeed5280d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 12:55:06 -0800 Subject: [PATCH 0253/1483] Don't accumulate animations with activators --- apps/openmw/mwmechanics/character.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3899b05ab7..42ab78d4f0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -83,9 +83,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); getStateInfo(mState, &mCurrentGroup); - /* Accumulate along X/Y only for now, until we can figure out how we should - * handle knockout and death which moves the character down. */ - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + { + /* Don't accumulate with activators (they don't get moved). */ + mAnimation->setAccumulation(Ogre::Vector3::ZERO); + } + else + { + /* Accumulate along X/Y only for now, until we can figure out how we should + * handle knockout and death which moves the character down. */ + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + } if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", loop); } From 347a734364fa28e045bc1809b3e0a9ca540ca870 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Tue, 5 Feb 2013 22:06:36 +0100 Subject: [PATCH 0254/1483] Move OpenDialog to editor and use it in startup dialogue. Remove debug output from DataFilesList. --- apps/opencs/editor.cpp | 32 +++++++++++----------- apps/opencs/editor.hpp | 3 ++ apps/opencs/view/doc/view.cpp | 29 ++------------------ apps/opencs/view/doc/view.hpp | 5 ---- components/fileorderlist/datafileslist.cpp | 2 -- 5 files changed, 21 insertions(+), 50 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 7156db94e7..02b494d3db 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -15,6 +15,8 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); + + connect (&mOpenDialog, SIGNAL(accepted()), this, SLOT(openFiles())); } void CS::Editor::createDocument() @@ -36,26 +38,24 @@ void CS::Editor::createDocument() } void CS::Editor::loadDocument() +{ + mOpenDialog.show(); + mOpenDialog.raise(); + mOpenDialog.activateWindow(); +} + +void CS::Editor::openFiles() { mStartup.hide(); - - /// \todo open the ESX picker instead - /// \todo remove the manual record creation and load the ESX files instead - - std::ostringstream stream; - - stream << "Document" << (++mNewDocumentIndex); - - std::vector files; - files.push_back (stream.str()); - - CSMDoc::Document *document = mDocumentManager.addDocument (files, false); - + std::vector paths; + mOpenDialog.getFileList(paths); + CSMDoc::Document *document = mDocumentManager.addDocument(paths, false); + static const char *sGlobals[] = { "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 }; - + for (int i=0; sGlobals[i]; ++i) { ESM::Global record; @@ -64,9 +64,9 @@ void CS::Editor::loadDocument() record.mType = ESM::VT_Float; document->getData().getGlobals().add (record); } - + document->getData().merge(); /// \todo remove once proper ESX loading is implemented - + mViewManager.addView (document); } diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 0cd780f7fc..024475bf01 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -7,6 +7,7 @@ #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" +#include "view/doc/opendialog.hpp" namespace CS { @@ -19,6 +20,7 @@ namespace CS CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; + OpenDialog mOpenDialog; // not implemented Editor (const Editor&); @@ -36,6 +38,7 @@ namespace CS void createDocument(); void loadDocument(); + void openFiles(); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 146e6634e4..f5cc3d85b0 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -14,7 +14,6 @@ #include "../tools/subviews.hpp" -#include "opendialog.hpp" #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -32,12 +31,8 @@ void CSVDoc::View::setupFileMenu() QAction *new_ = new QAction (tr ("New"), this); connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); file->addAction (new_); - - mOpen = new QAction(tr ("&Open"), this); - connect (mOpen, SIGNAL (triggered()), this, SLOT (open())); - file->addAction (mOpen); - QAction *open = new QAction (tr ("Open"), this); + QAction *open = new QAction (tr ("&Open"), this); connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest())); file->addAction (open); @@ -119,7 +114,7 @@ void CSVDoc::View::updateActions() } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) -: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), mOpenDialog(0) +: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { setDockOptions (QMainWindow::AllowNestedDocks); @@ -214,26 +209,6 @@ void CSVDoc::View::save() mDocument->save(); } -void CSVDoc::View::open() -{ - if (!mOpenDialog) { - mOpenDialog = new OpenDialog(this); - connect(mOpenDialog, SIGNAL(accepted()), this, SLOT(openNewFiles())); - } - - mOpenDialog->show(); - mOpenDialog->raise(); - mOpenDialog->activateWindow(); -} - -void CSVDoc::View::openNewFiles() -{ - std::vector paths; - mOpenDialog->getFileList(paths); - //FIXME load new files - -} - void CSVDoc::View::verify() { addSubView (mDocument->verify()); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index bb3763bb94..05d7210dce 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -9,7 +9,6 @@ #include "subviewfactory.hpp" class QAction; -class OpenDialog; namespace CSMDoc { @@ -37,12 +36,10 @@ namespace CSVDoc QAction *mUndo; QAction *mRedo; QAction *mSave; - QAction *mOpen; QAction *mVerify; std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; - OpenDialog * mOpenDialog; // not implemented View (const View&); @@ -97,8 +94,6 @@ namespace CSVDoc void newView(); - void open(); - void openNewFiles(); void save(); void verify(); diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index 38e0bfb1a5..d25060baaf 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -204,13 +204,11 @@ void DataFilesList::selectedFiles(std::vector& paths) foreach (const QString &path, masterPaths) { paths.push_back(path.toStdString()); - cerr << path.toStdString() << endl; } QStringList pluginPaths = mPluginsModel->checkedItemsPaths(); foreach (const QString &path, pluginPaths) { paths.push_back(path.toStdString()); - cerr << path.toStdString() << endl; } } From 8c0bb1ff4d26567ff4eb1a96a5e70e0f9c5ec227 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 14:02:14 -0800 Subject: [PATCH 0255/1483] Rotate movement in the movement solver --- apps/openmw/mwmechanics/character.cpp | 7 ------- apps/openmw/mwworld/physicssystem.cpp | 11 +++++++++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 42ab78d4f0..f1f6280e5b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -184,13 +184,6 @@ Ogre::Vector3 CharacterController::update(float duration) } mSkipAnim = false; - const ESM::Position &refpos = mPtr.getRefData().getPosition(); - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - return movement; } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 2d83c9a040..7020c8fb2e 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -80,10 +80,17 @@ namespace MWWorld } public: - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, OEngine::Physic::PhysicEngine *engine) { - Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + const ESM::Position &refpos = ptr.getRefData().getPosition(); + Ogre::Vector3 position(refpos.pos); + + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; /* Anything to collide with? */ OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); From 86d65519e370041b7b9422bb85a188eadba96c56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 23:57:30 +0100 Subject: [PATCH 0256/1483] Settings window fix --- apps/openmw/mwgui/settingswindow.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 75fc2b7a21..eaea022c0c 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -247,10 +247,10 @@ namespace MWGui mInvertYButton->setCaptionWithReplacing(Settings::Manager::getBool("invert y axis", "Input") ? "#{sOn}" : "#{sOff}"); - mShadersButton->setCaption (Settings::Manager::getBool("shaders", "Objects") ? "on" : "off"); + mShadersButton->setCaptionWithReplacing (Settings::Manager::getBool("shaders", "Objects") ? "#{sOn}" : "#{sOff}"); mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); - mRefractionButton->setCaption (Settings::Manager::getBool("refraction", "Water") ? "on" : "off"); + mRefractionButton->setCaptionWithReplacing (Settings::Manager::getBool("refraction", "Water") ? "#{sOn}" : "#{sOff}"); if (!MWRender::RenderingManager::waterShaderSupported()) { @@ -434,14 +434,17 @@ namespace MWGui void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) { - std::string val = static_cast(_sender)->getCaption(); - if (val == "off") - val = "on"; - else - val = "off"; - static_cast(_sender)->setCaption (val); + std::string on = mWindowManager.getGameSettingString("sOn", "On"); + std::string off = mWindowManager.getGameSettingString("sOff", "On"); - if (val == "off") + std::string val = static_cast(_sender)->getCaption(); + if (val == off) + val = on; + else + val = off; + static_cast(_sender)->setCaptionWithReplacing (val); + + if (val == off) { Settings::Manager::setBool("shaders", "Objects", false); From ee3764e9b34c1da280fc48a65a08225ffca0060f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 15:07:48 -0800 Subject: [PATCH 0257/1483] Increase max slope to 60. 45 is too low. --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7020c8fb2e..9517715b61 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -21,7 +21,7 @@ using namespace Ogre; namespace MWWorld { - static const float sMaxSlope = 45.0f; + static const float sMaxSlope = 60.0f; class MovementSolver { From 6e3c016351ed60c3b029d5e6b5ae605be6883685 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 3 Feb 2013 17:42:58 +0100 Subject: [PATCH 0258/1483] Add archives to settings imported by mwiniimporter Add Morrowind.bsa by default. --- apps/mwiniimporter/importer.cpp | 33 +++++++++++++++++++++++++++++++++ apps/mwiniimporter/importer.hpp | 1 + apps/mwiniimporter/main.cpp | 5 +++++ 3 files changed, 39 insertions(+) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 077b62be1b..87a87f630c 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -777,6 +777,39 @@ void MwIniImporter::insertMultistrmap(multistrmap &cfg, std::string key, std::st cfg[key].push_back(value); } +void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) { + std::vector archives; + std::string baseArchive("Archives:Archive "); + std::string archive; + + // Search archives listed in ini file + multistrmap::iterator it = ini.begin(); + for(int i=0; it != ini.end(); i++) { + archive = baseArchive; + archive.append(this->numberToString(i)); + + it = ini.find(archive); + if(it == ini.end()) { + break; + } + + for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { + archives.push_back(*entry); + } + } + + cfg.erase("fallback-archive"); + cfg.insert( std::make_pair > ("fallback-archive", std::vector())); + + // Add Morrowind.bsa by default, since Vanilla loads this archive even if it + // does not appears in the ini file + cfg["fallback-archive"].push_back("Morrowind.bsa"); + + for(std::vector::iterator it=archives.begin(); it!=archives.end(); ++it) { + cfg["fallback-archive"].push_back(*it); + } +} + void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { std::vector esmFiles; std::vector espFiles; diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index c87fd3e164..6b99810bc3 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -23,6 +23,7 @@ class MwIniImporter { void merge(multistrmap &cfg, multistrmap &ini); void mergeFallback(multistrmap &cfg, multistrmap &ini); void importGameFiles(multistrmap &cfg, multistrmap &ini); + void importArchives(multistrmap &cfg, multistrmap &ini); void writeToFile(boost::iostreams::stream &out, multistrmap &cfg); private: diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index e90f26dd2c..c9d88c0bba 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -18,6 +18,7 @@ int main(int argc, char *argv[]) { ("cfg,c", bpo::value(), "openmw.cfg file") ("output,o", bpo::value()->default_value(""), "openmw.cfg file") ("game-files,g", "import esm and esp files") + ("no-archives,A", "disable bsa archives import") ("encoding,e", bpo::value()-> default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" @@ -76,6 +77,10 @@ int main(int argc, char *argv[]) { importer.importGameFiles(cfg, ini); } + if(!vm.count("no-archives")) { + importer.importArchives(cfg, ini); + } + std::cout << "write to: " << outputFile << std::endl; boost::iostreams::stream file(outputFile); importer.writeToFile(file, cfg); From a4f051e85a9e423b94759136db60753addc435ca Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 5 Feb 2013 20:38:15 +0100 Subject: [PATCH 0259/1483] Fix game files import --- apps/mwiniimporter/importer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 87a87f630c..fc9ce417c7 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -827,7 +827,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { } for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { - std::string filetype(entry->substr(entry->length()-4, 3)); + std::string filetype(entry->substr(entry->length()-3)); Misc::StringUtils::toLower(filetype); if(filetype.compare("esm") == 0) { From e217a3d25c1a7720d672ce748186db3ab09832ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 15:51:26 -0800 Subject: [PATCH 0260/1483] Silence some console spam --- apps/openmw/mwworld/physicssystem.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9517715b61..e6e4dd6765 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -143,9 +143,7 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) - std::cout<< "stepped" < Date: Tue, 5 Feb 2013 16:29:51 -0800 Subject: [PATCH 0261/1483] Use a vector of skeletons to handle animation sources --- apps/openmw/mwrender/animation.cpp | 96 ++++++++++++++++++++---------- apps/openmw/mwrender/animation.hpp | 5 ++ 2 files changed, 69 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0e906181c5..ad98efb14e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,6 +46,42 @@ Animation::~Animation() } +Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) +{ + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + Ogre::SkeletonPtr skel = skelMgr.getByName(name); + if(skel.isNull()) + { + std::cerr<< "Failed to get skeleton source "<touch(); + mSkeletonSources.push_back(skel); + + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty() || !Ogre::any_cast(data)) + continue; + + for(int i = 0;i < skel->getNumAnimations();i++) + { + Ogre::Animation *anim = skel->getAnimation(i); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+anim->getName()); + if(!groupdata.isEmpty()) + mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + } + + return bone; + } + + return NULL; +} + void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { mInsert = node->createChildSceneNode(); @@ -63,51 +99,35 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model state->setLoop(false); } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); - // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; + boneiter.getNext()->setManuallyControlled(true); + Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); + if(bone) + { mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; - - asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+state->getAnimationName()); - if(!groupdata.isEmpty()) - mTextKeys[state->getAnimationName()] = Ogre::any_cast(groupdata); - } - - break; } - - // Set the bones as manually controlled since we're applying the - // transformations manually (needed if we want to apply an animation - // from one skeleton onto another). - boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); } } bool Animation::hasAnimation(const std::string &anim) { - return mEntityList.mSkelBase && mEntityList.mSkelBase->getSkeleton()->hasAnimation(anim); + for(std::vector::const_iterator iter(mSkeletonSources.begin());iter != mSkeletonSources.end();iter++) + { + if((*iter)->hasAnimation(anim)) + return true; + } + return false; } @@ -208,8 +228,20 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - mCurrentAnim = mEntityList.mSkelBase->getSkeleton()->getAnimation(groupname); - mCurrentKeys = &mTextKeys[groupname]; + bool found = false; + /* Look in reverse; last-inserted source has priority. */ + for(std::vector::const_reverse_iterator iter(mSkeletonSources.rbegin());iter != mSkeletonSources.rend();iter++) + { + if((*iter)->hasAnimation(groupname)) + { + mCurrentAnim = (*iter)->getAnimation(groupname); + mCurrentKeys = &mTextKeys[groupname]; + found = true; + break; + } + } + if(!found) + throw std::runtime_error("Failed to find animation "+groupname); reset(start); mPlaying = true; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 46a1ed88d2..62e93f1100 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -28,6 +28,8 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + std::vector mSkeletonSources; + NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; @@ -53,6 +55,9 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); + /* Inserts an additional skeleton into the animation source chain. Returns + * the bone representing the non-accum root from the base skeleton. */ + Ogre::Bone *insertSkeletonSource(const std::string &name); void createEntityList(Ogre::SceneNode *node, const std::string &model); From 16933e3926c368a575ee39e10d58cd65247c2d3a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 16:59:20 -0800 Subject: [PATCH 0262/1483] Scale the accumulation root translation --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ad98efb14e..63bd07beea 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -196,7 +196,7 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff); + mAccumRoot->translate(-posdiff * mAccumRoot->_getDerivedScale()); mLastPosition += posdiff; } return posdiff; @@ -220,7 +220,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(mStartPosition - mLastPosition); + mAccumRoot->setPosition((mStartPosition - mLastPosition) * mAccumRoot->_getDerivedScale()); } } From 054ef3113a8c28fd3cd59c19a60309d4cd1098ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:15:40 -0800 Subject: [PATCH 0263/1483] Check existing skeleton sources if the current one has no animation root --- apps/openmw/mwrender/animation.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 63bd07beea..baca70e37d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -108,10 +108,28 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model boneiter.getNext()->setManuallyControlled(true); Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); + if(!bone) + { + for(std::vector::const_iterator iter(mSkeletonSources.begin()); + !bone && iter != mSkeletonSources.end();iter++) + { + Ogre::Skeleton::BoneIterator boneiter = (*iter)->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(!data.isEmpty() && Ogre::any_cast(data)) + break; + + bone = NULL; + } + } + } if(bone) { mAccumRoot = mInsert; - mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mNonAccumRoot = skelinst->getBone(bone->getName()); mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; From c839502743697f9caa67ee60aec8e90e6f47f6d0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:16:45 -0800 Subject: [PATCH 0264/1483] Setup base_anim.nif as an initial skeleton source for biped creatures --- apps/openmw/mwrender/creatureanimation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 34b09c0d06..094281c46b 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -23,9 +23,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->mBase->mModel; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + insertSkeletonSource("meshes\\base_anim.nif"); - createEntityList(mPtr.getRefData().getBaseNode(), mesh); + createEntityList(mPtr.getRefData().getBaseNode(), "meshes\\"+ref->mBase->mModel); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; From 8b1e7b95ba4637cf01b65a1254f3e76b0cd55c77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:55:12 -0800 Subject: [PATCH 0265/1483] Attempt to load the skeleton source if it doesn't yet exist --- apps/openmw/mwrender/animation.cpp | 9 +++++++-- components/nifogre/ogre_nif_loader.cpp | 27 ++++++++++++++++++++++++++ components/nifogre/ogre_nif_loader.hpp | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index baca70e37d..f0ba8d654c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -52,8 +52,13 @@ Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) Ogre::SkeletonPtr skel = skelMgr.getByName(name); if(skel.isNull()) { - std::cerr<< "Failed to get skeleton source "<touch(); mSkeletonSources.push_back(skel); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b878c29f40..c7f6ac50da 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1250,6 +1250,33 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } +bool Loader::createSkeleton(const std::string &name, const std::string &group) +{ + Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); + Nif::NIFFile &nif = *pnif.get(); + if(nif.numRecords() < 1) + { + nif.warn("Found no NIF records in "+name+"."); + return false; + } + + // The first record is assumed to be the root node + Nif::Record const *r = nif.getRecord(0); + assert(r != NULL); + + Nif::Node const *node = dynamic_cast(r); + if(node == NULL) + { + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return false; + } + + NIFSkeletonLoader skelldr; + return skelldr.createSkeleton(name, group, node); +} + + /* 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 in the file was given a separate bone in a skeleton. Unfortunately diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 12be522332..0064defe29 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -77,6 +77,8 @@ public: static EntityList createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); + + static bool createSkeleton(const std::string &name, const std::string &group="General"); }; } From 535cd8360fd49ac805b7574529267e20559bbfb6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 18:09:43 -0800 Subject: [PATCH 0266/1483] Load extra animations for NPCs --- apps/openmw/mwrender/npcanimation.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 18f44c87ca..74b3945fa1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -120,6 +120,14 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + if(!mNpc->isMale() && !isBeast) + insertSkeletonSource("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + insertSkeletonSource("meshes\\argonian_swimkna.nif"); + + if(mNpc->mModel.length() > 0) + insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + float scale = race->mData.mHeight.mMale; if (!mNpc->isMale()) { scale = race->mData.mHeight.mFemale; From 18b70084095facb95a25011a891f167f6a9966cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 18:25:09 -0800 Subject: [PATCH 0267/1483] Better fix some scaling issues --- apps/openmw/mwrender/animation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.cpp | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f0ba8d654c..019217ca69 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -219,7 +219,7 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff * mAccumRoot->_getDerivedScale()); + mAccumRoot->translate(-posdiff); mLastPosition += posdiff; } return posdiff; @@ -243,7 +243,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition((mStartPosition - mLastPosition) * mAccumRoot->_getDerivedScale()); + mAccumRoot->setPosition(mStartPosition*mNonAccumRoot->_getDerivedScale() - mLastPosition); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 74b3945fa1..120996a70a 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -83,6 +83,11 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); + float scale = race->mData.mHeight.mMale; + if(!mNpc->isMale()) + scale = race->mData.mHeight.mFemale; + node->scale(Ogre::Vector3(scale)); + mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; @@ -128,12 +133,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor if(mNpc->mModel.length() > 0) insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - float scale = race->mData.mHeight.mMale; - if (!mNpc->isMale()) { - scale = race->mData.mHeight.mFemale; - } - mInsert->scale(scale, scale, scale); - updateParts(); } From fc307e64b03d47e38f91cdcb4ac181f7fdfb0d6d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 19:05:07 -0800 Subject: [PATCH 0268/1483] Add swimming states --- apps/openmw/mwmechanics/character.cpp | 18 +++++++++++++----- apps/openmw/mwmechanics/character.hpp | 6 ++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f1f6280e5b..f119ceb69f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -46,12 +46,18 @@ static const struct { { CharState_Idle7, "idle7" }, { CharState_Idle8, "idle8" }, { CharState_Idle9, "idle9" }, + { CharState_IdleSwim, "idleswim" }, { CharState_WalkForward, "walkforward" }, { CharState_WalkBack, "walkback" }, { CharState_WalkLeft, "walkleft" }, { CharState_WalkRight, "walkright" }, + { CharState_SwimWalkForward, "swimwalkforward" }, + { CharState_SwimWalkBack, "swimwalkback" }, + { CharState_SwimWalkLeft, "swimwalkleft" }, + { CharState_SwimWalkRight, "swimwalkright" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -157,21 +163,23 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) - setState(CharState_WalkRight, true); + setState((inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); else if(vec.x < 0.0f) - setState(CharState_WalkLeft, true); + setState((inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); } else if(vec.y > 0.0f) - setState(CharState_WalkForward, true); + setState((inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); else if(vec.y < 0.0f) - setState(CharState_WalkBack, true); + setState((inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) - setState(CharState_Idle, true); + setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } Ogre::Vector3 movement = Ogre::Vector3::ZERO; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index adb6364a0c..535680fa15 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -23,12 +23,18 @@ enum CharacterState { CharState_Idle7, CharState_Idle8, CharState_Idle9, + CharState_IdleSwim, CharState_WalkForward, CharState_WalkBack, CharState_WalkLeft, CharState_WalkRight, + CharState_SwimWalkForward, + CharState_SwimWalkBack, + CharState_SwimWalkLeft, + CharState_SwimWalkRight, + /* Must be last! */ CharState_Death1, CharState_Death2, From 9cf30f39bd1d3b1c17450d2929c75e98b76318de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 19:45:51 -0800 Subject: [PATCH 0269/1483] Don't apply gravity when swimming --- apps/openmw/mwworld/physicssystem.cpp | 32 +++++++++++++++------------ apps/openmw/mwworld/physicssystem.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index e6e4dd6765..b30d9a7b24 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -81,7 +81,7 @@ namespace MWWorld public: static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, - OEngine::Physic::PhysicEngine *engine) + bool gravity, OEngine::Physic::PhysicEngine *engine) { const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); @@ -100,8 +100,9 @@ namespace MWWorld traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - float verticalVelocity = physicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; + float verticalVelocity = (gravity ? physicActor->getVerticalForce() : + horizontalVelocity.z); Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); @@ -115,18 +116,21 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f) + if(gravity) { - if(getSlope(trace.planenormal) > sMaxSlope) + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f) { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + if(getSlope(trace.planenormal) > sMaxSlope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } } } @@ -339,9 +343,9 @@ namespace MWWorld } } - Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity) { - return MovementSolver::move(ptr, movement, time, mEngine); + return MovementSolver::move(ptr, movement, time, gravity, mEngine); } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index d897c78e9e..c1f70f2ca9 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -35,7 +35,7 @@ namespace MWWorld bool toggleCollisionMode(); - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fb31c54ab2..b599076839 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -849,12 +849,12 @@ namespace MWWorld player = iter; continue; } - Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration); + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, !isSwimming(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { - Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration); + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } } From dfd16c44245c6577fca1e05522974fbdb9a6bde5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 12:39:26 -0800 Subject: [PATCH 0270/1483] Fix movement rotations --- apps/openmw/mwworld/physicssystem.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b30d9a7b24..c42214fb20 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -86,20 +86,33 @@ namespace MWWorld const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - /* Anything to collide with? */ OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); if(!physicActor || !physicActor->getCollisionMode()) - return position + movement; + { + // FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why? + return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement; + } traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + if(!gravity) + { + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement; + } + else + { + movement = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * + movement; + } + Ogre::Vector3 horizontalVelocity = movement/time; float verticalVelocity = (gravity ? physicActor->getVerticalForce() : horizontalVelocity.z); From bdda7278c4acf52b9d23950d64314d39d3f86f2a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 12:56:30 -0800 Subject: [PATCH 0271/1483] Use 3/4ths of the physic actor's height to test if swimming --- apps/openmw/mwworld/worldimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b599076839..55270280d1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1336,8 +1336,9 @@ namespace MWWorld float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - /// \fixme should rely on object height - pos.z += 30; + /// \fixme 3/4ths submerged? + const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); + if(actor) pos.z += actor->getHalfExtents().z * 1.5; return isUnderwater(*object.getCell()->mCell, pos); } From 04524fbf92fd639751daf75a0724b6aed9881249 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 15:23:52 -0800 Subject: [PATCH 0272/1483] Don't scale the movement vector up --- apps/openmw/mwclass/npc.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6069e3b7c7..3666d9d6ba 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -311,14 +311,10 @@ namespace MWClass Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const { - Ogre::Vector3 vector (0, 0, 0); - - vector.x = getMovementSettings (ptr).mLeftRight * 127; - vector.y = getMovementSettings (ptr).mForwardBackward * 127; - vector.z = getMovementSettings(ptr).mUpDown * 127; - - //if (getStance (ptr, Run, false)) - // vector *= 2; + Ogre::Vector3 vector; + vector.x = getMovementSettings(ptr).mLeftRight; + vector.y = getMovementSettings(ptr).mForwardBackward; + vector.z = getMovementSettings(ptr).mUpDown; return vector; } From cbaf489eb6436681d4cb2893749f68a9d4510009 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 16:53:52 -0800 Subject: [PATCH 0273/1483] Add running states --- apps/openmw/mwmechanics/character.cpp | 27 +++++++++++++++++++++++---- apps/openmw/mwmechanics/character.hpp | 10 ++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f119ceb69f..b6e96bdf5e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -58,6 +58,16 @@ static const struct { { CharState_SwimWalkLeft, "swimwalkleft" }, { CharState_SwimWalkRight, "swimwalkright" }, + { CharState_RunForward, "runforward" }, + { CharState_RunBack, "runback" }, + { CharState_RunLeft, "runleft" }, + { CharState_RunRight, "runright" }, + + { CharState_SwimRunForward, "swimrunforward" }, + { CharState_SwimRunBack, "swimrunback" }, + { CharState_SwimRunLeft, "swimrunleft" }, + { CharState_SwimRunRight, "swimrunright" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -164,18 +174,27 @@ Ogre::Vector3 CharacterController::update(float duration) const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) - setState((inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); + setState(isrunning ? + (inwater ? CharState_SwimRunRight : CharState_RunRight) : + (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); else if(vec.x < 0.0f) - setState((inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + setState(isrunning ? + (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : + (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); } else if(vec.y > 0.0f) - setState((inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); else if(vec.y < 0.0f) - setState((inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 535680fa15..d67964b846 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -35,6 +35,16 @@ enum CharacterState { CharState_SwimWalkLeft, CharState_SwimWalkRight, + CharState_RunForward, + CharState_RunBack, + CharState_RunLeft, + CharState_RunRight, + + CharState_SwimRunForward, + CharState_SwimRunBack, + CharState_SwimRunLeft, + CharState_SwimRunRight, + /* Must be last! */ CharState_Death1, CharState_Death2, From 814969dcae6ab8428b582bc86921ca38d072274e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Feb 2013 02:23:41 +0100 Subject: [PATCH 0274/1483] Cache integrity check uses relative paths, so that changing the build folder works without reset --- extern/shiny/Main/Factory.cpp | 99 ++++++++++++++++++++--------------- extern/shiny/Main/Factory.hpp | 2 + 2 files changed, 58 insertions(+), 43 deletions(-) diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index c63a9e367a..21f13e30b6 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -50,7 +50,7 @@ namespace sh { assert(mCurrentLanguage != Language_None); - bool anyShaderDirty = false; + bool removeBinaryCache = false; if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt")) { @@ -182,57 +182,33 @@ namespace sh } } - std::string sourceFile = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); + std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); + std::string sourceRelative = it->second->findChild("source")->getValue(); ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile, - sourceFile, + sourceAbsolute, mPlatform->getBasePath(), it->first, &mGlobalSettings); - int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceFile)); - mShadersLastModifiedNew[sourceFile] = lastModified; - if (mShadersLastModified.find(sourceFile) != mShadersLastModified.end() - && mShadersLastModified[sourceFile] != lastModified) + int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); + mShadersLastModifiedNew[sourceRelative] = lastModified; + if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) { - // delete any outdated shaders based on this shader set. - if ( boost::filesystem::exists(mPlatform->getCacheFolder()) - && boost::filesystem::is_directory(mPlatform->getCacheFolder())) + if (mShadersLastModified[sourceRelative] != lastModified) { - boost::filesystem::directory_iterator end_iter; - for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter) - { - if (boost::filesystem::is_regular_file(dir_iter->status()) ) - { - boost::filesystem::path file = dir_iter->path(); - - std::string pathname = file.filename().string(); - - // get first part of filename, e.g. main_fragment_546457654 -> main_fragment - // there is probably a better method for this... - std::vector tokens; - boost::split(tokens, pathname, boost::is_any_of("_")); - tokens.erase(--tokens.end()); - std::string shaderName; - for (std::vector::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();) - { - shaderName += *(vector_iter++); - if (vector_iter != tokens.end()) - shaderName += "_"; - } - - if (shaderName == it->first) - { - boost::filesystem::remove(file); - std::cout << "Removing outdated file: " << file << std::endl; - } - } - } + // delete any outdated shaders based on this shader set + removeCache (it->first); + // remove the whole binary cache (removing only the individual shaders does not seem to be possible at this point with OGRE) + removeBinaryCache = true; } - - anyShaderDirty = true; } - + else + { + // if we get here, this is either the first run or a new shader file was added + // in both cases we can safely delete + removeCache (it->first); + } mShaderSets.insert(std::make_pair(it->first, newSet)); } } @@ -326,7 +302,7 @@ namespace sh } } - if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !anyShaderDirty) + if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache) { std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; if (boost::filesystem::exists(file)) @@ -613,4 +589,41 @@ namespace sh assert(m); m->createForConfiguration (configuration, 0); } + + void Factory::removeCache(const std::string& pattern) + { + if ( boost::filesystem::exists(mPlatform->getCacheFolder()) + && boost::filesystem::is_directory(mPlatform->getCacheFolder())) + { + boost::filesystem::directory_iterator end_iter; + for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter) + { + if (boost::filesystem::is_regular_file(dir_iter->status()) ) + { + boost::filesystem::path file = dir_iter->path(); + + std::string pathname = file.filename().string(); + + // get first part of filename, e.g. main_fragment_546457654 -> main_fragment + // there is probably a better method for this... + std::vector tokens; + boost::split(tokens, pathname, boost::is_any_of("_")); + tokens.erase(--tokens.end()); + std::string shaderName; + for (std::vector::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();) + { + shaderName += *(vector_iter++); + if (vector_iter != tokens.end()) + shaderName += "_"; + } + + if (shaderName == pattern) + { + boost::filesystem::remove(file); + std::cout << "Removing outdated shader: " << file << std::endl; + } + } + } + } + } } diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp index 1062c079c9..6d4175c976 100644 --- a/extern/shiny/Main/Factory.hpp +++ b/extern/shiny/Main/Factory.hpp @@ -202,6 +202,8 @@ namespace sh MaterialInstance* findInstance (const std::string& name); MaterialInstance* searchInstance (const std::string& name); + + void removeCache (const std::string& pattern); }; } From a8f0ce43a5e1d6f50758c8fb8663ac6082f892d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 17:51:47 -0800 Subject: [PATCH 0275/1483] Add a run key --- apps/openmw/mwinput/inputmanagerimp.cpp | 8 ++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ apps/openmw/mwworld/player.cpp | 6 ++++++ apps/openmw/mwworld/player.hpp | 1 + 4 files changed, 17 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 991cf4f518..4868eedae9 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -301,6 +301,11 @@ namespace MWInput else mPlayer.setUpDown (0); + if(actionIsActive(A_Run)) + mPlayer.setRunState(true); + else + mPlayer.setRunState(false); + if (mControlSwitch["playerviewswitch"]) { // work around preview mode toggle when pressing Alt+Tab @@ -690,6 +695,7 @@ namespace MWInput defaultKeyBindings[A_ToggleSpell] = OIS::KC_R; defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1; defaultKeyBindings[A_Console] = OIS::KC_F2; + defaultKeyBindings[A_Run] = OIS::KC_LSHIFT; defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL; defaultKeyBindings[A_AutoMove] = OIS::KC_Q; defaultKeyBindings[A_Jump] = OIS::KC_E; @@ -756,6 +762,7 @@ namespace MWInput descriptions[A_ToggleWeapon] = "sReady_Weapon"; descriptions[A_ToggleSpell] = "sReady_Magic"; descriptions[A_Console] = "sConsoleTitle"; + descriptions[A_Run] = "sRun"; descriptions[A_Crouch] = "sCrouch_Sneak"; descriptions[A_AutoMove] = "sAuto_Run"; descriptions[A_Jump] = "sJump"; @@ -804,6 +811,7 @@ namespace MWInput ret.push_back(A_MoveLeft); ret.push_back(A_MoveRight); ret.push_back(A_TogglePOV); + ret.push_back(A_Run); ret.push_back(A_Crouch); ret.push_back(A_Activate); ret.push_back(A_ToggleWeapon); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f285..6fd6441da5 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -239,6 +239,8 @@ namespace MWInput A_ToggleHUD, + A_Run, + A_Last // Marker for the last item }; }; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 3414ba4489..76d44a5d7b 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -71,6 +71,12 @@ namespace MWWorld MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value; } + void Player::setRunState(bool run) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).setStance(ptr, MWWorld::Class::Run, run); + } + void Player::toggleRunning() { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 1c1ef76cf0..4ef4d67717 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -65,6 +65,7 @@ namespace MWWorld void setForwardBackward (int value); void setUpDown(int value); + void setRunState(bool run); void toggleRunning(); }; } From ebc7bc9427da101a1b71223706d74fde1a56a845 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 18:22:16 -0800 Subject: [PATCH 0276/1483] Rename A_AlwaysRun to A_Run Note that there is an "always run" key, but its functionality is handled by A_ToggleWalk. --- apps/openmw/mwinput/inputmanagerimp.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 6fd6441da5..3af39911cb 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -207,7 +207,7 @@ namespace MWInput A_Journal, //Journal A_Weapon, //Draw/Sheath weapon A_Spell, //Ready/Unready Casting - A_AlwaysRun, //Toggle Always Run + A_Run, //Run when held A_CycleSpellLeft, //cycling through spells A_CycleSpellRight, A_CycleWeaponLeft,//Cycling through weapons @@ -239,8 +239,6 @@ namespace MWInput A_ToggleHUD, - A_Run, - A_Last // Marker for the last item }; }; From e577ee2de815d9880ab66cf208c03c6c259cec0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:44:58 -0800 Subject: [PATCH 0277/1483] Add a method to set/retrieve being on the ground --- apps/openmw/mwworld/physicssystem.cpp | 13 +++++++++---- apps/openmw/mwworld/worldimp.cpp | 18 +++++++----------- libs/openengine/bullet/physic.cpp | 11 ++++++++++- libs/openengine/bullet/physic.hpp | 5 +++++ 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c42214fb20..c5c634d79d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -9,6 +9,9 @@ #include #include +#include +#include + #include //#include "../mwbase/world.hpp" // FIXME @@ -129,6 +132,7 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; + bool onground = false; if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); @@ -155,10 +159,11 @@ namespace MWWorld remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions - if(trace.fraction != 1.0f) + if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + onground = getSlope(currentNormal) <= sMaxSlope; + if(!onground || currentNormal == lastNormal) { if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { @@ -184,8 +189,8 @@ namespace MWWorld } while(iterations < maxIterations && remainingTime != 0.0f); verticalVelocity = clippedVelocity.z; - verticalVelocity -= time*400; - physicActor->setVerticalForce(verticalVelocity); + physicActor->setVerticalForce(verticalVelocity - time*400.0f); + physicActor->setOnGround(onground); return newPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 55270280d1..085add7c9e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1,5 +1,7 @@ #include "worldimp.hpp" +#include + #include #include @@ -1366,20 +1368,14 @@ namespace MWWorld { Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); - Ogre::Vector3 playerPos; - float* pos = mPlayer->getPlayer ().getRefData ().getPosition ().pos; - playerPos.x = pos[0]; - playerPos.y = pos[1]; - playerPos.z = pos[2]; + RefData &refdata = mPlayer->getPlayer().getRefData(); + const OEngine::Physic::PhysicActor *physact = mPhysEngine->getCharacter(refdata.getHandle()); + Ogre::Vector3 playerPos(refdata.getPosition().pos); - std::pair hit = - mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); - bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); - - if (!isOnGround || isUnderwater (*currentCell->mCell, playerPos)) + if(!physact->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) return 2; - if (currentCell->mCell->mData.mFlags & ESM::Cell::NoSleep) + if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; return 0; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 1ae916f81c..95313cdba4 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -28,7 +28,7 @@ namespace Physic }; PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -180,6 +180,15 @@ namespace Physic return verticalForce; } + void PhysicActor::setOnGround(bool grounded) + { + onGround = grounded; + } + + bool PhysicActor::getOnGround() const + { + return collisionMode && onGround; + } void PhysicActor::runPmove(){ Pmove(pmove); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index daf1c09f2b..4bc926b8ab 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -132,6 +132,10 @@ namespace Physic */ float getVerticalForce() const; + void setOnGround(bool grounded); + + bool getOnGround() const; + /** * Runs pmove for this PhysicActor */ @@ -152,6 +156,7 @@ namespace Physic btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; float verticalForce; + bool onGround; bool collisionMode; std::string mMesh; PhysicEngine* mEngine; From 923d0d6eb4030cac4a1198b85a70ebcc62f58788 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:47:09 -0800 Subject: [PATCH 0278/1483] Fix up some header includes --- apps/openmw/mwrender/debugging.cpp | 2 ++ apps/openmw/mwrender/debugging.hpp | 9 ++++++++- apps/openmw/mwrender/objects.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwworld/physicssystem.hpp | 5 ++++- libs/openengine/bullet/pmove.cpp | 4 ++-- libs/openengine/bullet/pmove.h | 10 ++++++++-- libs/openengine/bullet/trace.cpp | 8 ++------ libs/openengine/bullet/trace.h | 14 +++++++++++--- 9 files changed, 40 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 1548cc1b0f..2061b74d7f 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index d312b6d546..07e5f0a3f4 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -13,6 +12,14 @@ namespace ESM struct Pathgrid; } +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} + namespace Ogre { class Camera; diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 48632dba83..b2bdac683f 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -2,6 +2,7 @@ #define _GAME_RENDER_OBJECTS_H #include +#include #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 082b561ef5..1551f73b83 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index c1f70f2ca9..0b4ccd52fd 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -1,12 +1,15 @@ #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H +#include + #include -#include "ptr.hpp" #include +#include "ptr.hpp" namespace MWWorld { + class World; class PhysicsSystem { diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 8d98a482e6..9cd76968a1 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -7,8 +7,6 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include "pmove.h" - - //#include "bprintf.h" //#include "..\..\ESMParser\ESMParser\CELL.h" @@ -22,6 +20,8 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include +#include "trace.h" + //SceneInstance* global_lastscene = NULL; // Forward declaration: diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index fa303184e5..29a0504712 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -8,8 +8,6 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include #include -#include "trace.h" -#include "physic.hpp" #include @@ -18,6 +16,14 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. // Forwards-declare it! +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} + /*#ifndef COMPILING_PMOVE #include "Scene.h" extern SceneInstance* global_lastscene; diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 9f53985745..847059530c 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -1,14 +1,10 @@ #include "trace.h" - - #include - - - - +#include "physic.hpp" +#include "pmove.h" void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 1bfe0c7178..462d062ebe 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -4,9 +4,17 @@ #include #include -#include -#include -#include "pmove.h" + +#include + + +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} enum traceWorldType From 8de2d24d0ef2094174ee0ad77b928519012a9ba9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:57:59 -0800 Subject: [PATCH 0279/1483] Restore old ground check --- apps/openmw/mwworld/physicssystem.cpp | 5 +---- apps/openmw/mwworld/worldimp.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c5c634d79d..9262aa3c5c 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -132,7 +132,6 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; - bool onground = false; if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); @@ -162,8 +161,7 @@ namespace MWWorld if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { @@ -190,7 +188,6 @@ namespace MWWorld verticalVelocity = clippedVelocity.z; physicActor->setVerticalForce(verticalVelocity - time*400.0f); - physicActor->setOnGround(onground); return newPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 085add7c9e..6e063e1fed 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1369,10 +1369,12 @@ namespace MWWorld Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); RefData &refdata = mPlayer->getPlayer().getRefData(); - const OEngine::Physic::PhysicActor *physact = mPhysEngine->getCharacter(refdata.getHandle()); Ogre::Vector3 playerPos(refdata.getPosition().pos); - if(!physact->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) + std::pair hit = mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); + bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); + + if(!isOnGround || isUnderwater(*currentCell->mCell, playerPos)) return 2; if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) From 7d112e4d5c033b358638fb89255b4da9f5ed12fe Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 11:33:08 +0100 Subject: [PATCH 0280/1483] rewrote logic of content file loading --- apps/opencs/model/doc/document.cpp | 28 ++++++++++++++++++---------- apps/opencs/model/doc/document.hpp | 3 ++- apps/opencs/model/world/data.cpp | 5 +++++ apps/opencs/model/world/data.hpp | 5 +++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 14e34d0baf..796135c3ff 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,15 +1,23 @@ #include "document.hpp" -#include +#include void CSMDoc::Document::load (const std::vector::const_iterator& begin, - const std::vector::const_iterator& end) + const std::vector::const_iterator& end, bool lastAsModified) { - for (std::vector::const_iterator iter (begin); iter!=end; ++iter) - std::cout << "pretending to load " << iter->string() << std::endl; + assert (begin!=end); - /// \todo load content files + std::vector::const_iterator end2 (end); + + if (lastAsModified) + --end2; + + for (std::vector::const_iterator iter (begin); iter!=end2; ++iter) + getData().loadFile (*iter, true); + + if (lastAsModified) + getData().loadFile (*end2, false); } void CSMDoc::Document::createBase() @@ -48,7 +56,7 @@ CSMDoc::Document::Document (const std::vector& files, b if (new_) --end; - load (files.begin(), end); + load (files.begin(), end, !new_); } if (new_ && files.size()==1) @@ -134,10 +142,10 @@ void CSMDoc::Document::saving() if (mSaveCount>15) { - mSaveCount = 0; - mSaveTimer.stop(); - mUndoStack.setClean(); - emit stateChanged (getState(), this); + mSaveCount = 0; + mSaveTimer.stop(); + mUndoStack.setClean(); + emit stateChanged (getState(), this); } } diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 28cc19d449..0162681bcb 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -41,7 +41,8 @@ namespace CSMDoc Document& operator= (const Document&); void load (const std::vector::const_iterator& begin, - const std::vector::const_iterator& end); + const std::vector::const_iterator& end, bool lastAsModified); + ///< \param lastAsModified Store the last file in Modified instead of merging it into Base. void createBase(); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a3522503e4..5d4e63b277 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -59,4 +59,9 @@ QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) void CSMWorld::Data::merge() { mGlobals.merge(); +} + +void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) +{ + std::cout << "pretending to load " << path.string() << std::endl; } \ No newline at end of file diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index f7748cb5da..8a6cd736b4 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include "idcollection.hpp" @@ -44,6 +46,9 @@ namespace CSMWorld void merge(); ///< Merge modified into base. + + void loadFile (const boost::filesystem::path& path, bool base); + ///< Merging content of a file into base or modified. }; } From adcaea464bda920b74ce9eea527eb4b004e41531 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 12:52:01 +0100 Subject: [PATCH 0281/1483] basic globals record loading --- apps/opencs/editor.cpp | 20 ++--------- apps/opencs/model/world/data.cpp | 24 ++++++++++++- apps/opencs/model/world/idcollection.cpp | 2 +- apps/opencs/model/world/idcollection.hpp | 45 ++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 22 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 02b494d3db..9161072f80 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -15,7 +15,7 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); - + connect (&mOpenDialog, SIGNAL(accepted()), this, SLOT(openFiles())); } @@ -50,23 +50,7 @@ void CS::Editor::openFiles() std::vector paths; mOpenDialog.getFileList(paths); CSMDoc::Document *document = mDocumentManager.addDocument(paths, false); - - static const char *sGlobals[] = - { - "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 - }; - - for (int i=0; sGlobals[i]; ++i) - { - ESM::Global record; - record.mId = sGlobals[i]; - record.mValue = i==0 ? 1 : 0; - record.mType = ESM::VT_Float; - document->getData().getGlobals().add (record); - } - - document->getData().merge(); /// \todo remove once proper ESX loading is implemented - + mViewManager.addView (document); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 5d4e63b277..9b89533a64 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -5,6 +5,7 @@ #include +#include #include #include "idtable.hpp" @@ -63,5 +64,26 @@ void CSMWorld::Data::merge() void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) { - std::cout << "pretending to load " << path.string() << std::endl; + ESM::ESMReader reader; + /// \todo set encoder + reader.open (path.string()); + + // Note: We do not need to send update signals here, because at this point the model is not connected + // to any view. + while (reader.hasMoreRecs()) + { + ESM::NAME n = reader.getRecName(); + reader.getRecHeader(); + + switch (n.val) + { + case ESM::REC_GLOB: mGlobals.load (reader, base); break; + + + default: + + /// \todo throw an exception instead, once all records are implemented + reader.skipRecord(); + } + } } \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp index fc4bb1ef65..5ea9532790 100644 --- a/apps/opencs/model/world/idcollection.cpp +++ b/apps/opencs/model/world/idcollection.cpp @@ -3,4 +3,4 @@ CSMWorld::IdCollectionBase::IdCollectionBase() {} -CSMWorld::IdCollectionBase::~IdCollectionBase() {} \ No newline at end of file +CSMWorld::IdCollectionBase::~IdCollectionBase() {} diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 963997924a..dd8fbcb382 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -11,9 +11,12 @@ #include -#include "columnbase.hpp" +#include + #include +#include "columnbase.hpp" + namespace CSMWorld { class IdCollectionBase @@ -67,9 +70,11 @@ namespace CSMWorld virtual std::string getId (const RecordBase& record) const = 0; ///< Return ID for \a record. /// - /// \attention Throw san exception, if the type of \a record does not match. + /// \attention Throws an exception, if the type of \a record does not match. virtual const RecordBase& getRecord (const std::string& id) const = 0; + + virtual void load (ESM::ESMReader& reader, bool base) = 0; }; ///< \brief Collection of ID-based records @@ -136,6 +141,8 @@ namespace CSMWorld virtual const RecordBase& getRecord (const std::string& id) const; + virtual void load (ESM::ESMReader& reader, bool base); + void addColumn (Column *column); }; @@ -309,6 +316,40 @@ namespace CSMWorld return (record2.isModified() ? record2.mModified : record2.mBase).mId; } + template + void IdCollection::load (ESM::ESMReader& reader, bool base) + { + std::string id = reader.getHNOString ("NAME"); + + /// \todo deal with deleted flag + + ESXRecordT record; + record.mId = id; + record.load (reader); + + int index = searchId (id); + + if (index==-1) + { + // new record + Record record2; + record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; + (base ? record2.mBase : record2.mModified) = record; + + appendRecord (record2); + } + else + { + // old record + Record& record2 = mRecords[index]; + + if (base) + record2.mBase = record; + else + record2.setModified (record); + } + } + template const RecordBase& IdCollection::getRecord (const std::string& id) const { From 21733e8181e11d23fc9358d6de2ca9fb61009d89 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 13:11:41 +0100 Subject: [PATCH 0282/1483] hide startup dialogue when opening open dialogue --- apps/opencs/editor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9161072f80..5cc659ff99 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -39,6 +39,7 @@ void CS::Editor::createDocument() void CS::Editor::loadDocument() { + mStartup.hide(); mOpenDialog.show(); mOpenDialog.raise(); mOpenDialog.activateWindow(); From c1cd8305bc9a01c2871aa097c6ad004dea8743c0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 13:13:06 +0100 Subject: [PATCH 0283/1483] a bit of cleanup for the previous commit --- apps/opencs/editor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 5cc659ff99..e2df365a29 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -47,7 +47,6 @@ void CS::Editor::loadDocument() void CS::Editor::openFiles() { - mStartup.hide(); std::vector paths; mOpenDialog.getFileList(paths); CSMDoc::Document *document = mDocumentManager.addDocument(paths, false); From dd2b7d5c63a050acf26a82399aecf9f967429b62 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 13:26:00 +0100 Subject: [PATCH 0284/1483] handle deleted records --- apps/opencs/model/world/idcollection.hpp | 56 +++++++++++++++++------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index dd8fbcb382..5a1d21ae4c 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -321,32 +321,54 @@ namespace CSMWorld { std::string id = reader.getHNOString ("NAME"); - /// \todo deal with deleted flag - - ESXRecordT record; - record.mId = id; - record.load (reader); - int index = searchId (id); - if (index==-1) + if (reader.isNextSub ("DELE")) { - // new record - Record record2; - record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; - (base ? record2.mBase : record2.mModified) = record; + reader.skipRecord(); - appendRecord (record2); + if (index==-1) + { + // deleting a record that does not exist + + // ignore it for now + + /// \todo report the problem to the user + } + else if (base) + { + removeRows (index, 1); + } + else + { + mRecords[index].mState = RecordBase::State_Deleted; + } } else { - // old record - Record& record2 = mRecords[index]; + ESXRecordT record; + record.mId = id; + record.load (reader); - if (base) - record2.mBase = record; + if (index==-1) + { + // new record + Record record2; + record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; + (base ? record2.mBase : record2.mModified) = record; + + appendRecord (record2); + } else - record2.setModified (record); + { + // old record + Record& record2 = mRecords[index]; + + if (base) + record2.mBase = record; + else + record2.setModified (record); + } } } From 0d4b0bfd9396846971f112c948f8334fb89f9dc4 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 7 Feb 2013 23:40:20 +0400 Subject: [PATCH 0285/1483] Trying to resolve sound issues on OS X with ffmpeg backend --- apps/openmw/CMakeLists.txt | 6 ++++++ apps/openmw/mwsound/ffmpeg_decoder.cpp | 1 + 2 files changed, 7 insertions(+) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e2cb0e5c41..b685c60831 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -125,6 +125,12 @@ if(APPLE) find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) target_link_libraries(openmw ${CARBON_FRAMEWORK} ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) + + if (FFMPEG_FOUND) + find_library(COREVIDEO_FRAMEWORK CoreVideo) + find_library(VDA_FRAMEWORK VideoDecodeAcceleration) + target_link_libraries(openmw ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK}) + endif() endif(APPLE) if(DPKG_PROGRAM) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 261a86ca60..00530a9628 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -160,6 +160,7 @@ void FFmpeg_Decoder::open(const std::string &fname) { if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; mStream = &mFormatCtx->streams[j]; break; } From fe0e6c452d300cb288e5174b41ea498462d4ccc1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 12:11:10 -0800 Subject: [PATCH 0286/1483] Remove the unneeded playerMove object from PhysicsSystem --- apps/openmw/mwworld/physicssystem.cpp | 34 +++++++-------------------- apps/openmw/mwworld/physicssystem.hpp | 19 +++++++++++---- apps/openmw/mwworld/scene.cpp | 1 + apps/openmw/mwworld/scene.hpp | 4 ++-- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9262aa3c5c..6c41d56e65 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -9,8 +9,9 @@ #include #include -#include -#include +#include +#include +#include #include @@ -25,6 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; + static const float sStepSize = 9.0f; class MovementSolver { @@ -35,13 +37,13 @@ namespace MWWorld { traceResults trace; // no initialization needed - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), - position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), + position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, verticalRotation, isInterior, engine); if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. @@ -197,20 +199,16 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { - - playerphysics = new playerMove; // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); - playerphysics->mEngine = mEngine; } PhysicsSystem::~PhysicsSystem() { delete mEngine; - delete playerphysics; - } + OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() { return mEngine; @@ -279,15 +277,8 @@ namespace MWWorld void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) { - playerphysics->hasWater = hasWater; - if(hasWater){ - playerphysics->waterHeight = waterHeight; - } for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { it->second->setCurrentWater(hasWater, waterHeight); - } - } btVector3 PhysicsSystem::getRayPoint(float extent) @@ -428,14 +419,8 @@ namespace MWWorld { // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow // start positions others than 0, 0, 0 - if (handle == "player") - { - playerphysics->ps.origin = position; - } - else - { + if (handle != "player") act->setPosition(position); - } } } @@ -474,7 +459,6 @@ namespace MWWorld bool PhysicsSystem::toggleCollisionMode() { - playerphysics->ps.move_type = (playerphysics->ps.move_type == PM_NOCLIP ? PM_NORMAL : PM_NOCLIP); for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { if (it->first=="player") diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 0b4ccd52fd..cbdd9935eb 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -1,15 +1,27 @@ #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H +#include + #include -#include -#include -#include "ptr.hpp" + +namespace OEngine +{ + namespace Render + { + class OgreRenderer; + } + namespace Physic + { + class PhysicEngine; + } +} namespace MWWorld { class World; + class Ptr; class PhysicsSystem { @@ -74,7 +86,6 @@ namespace MWWorld OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; bool mFreeFly; - playerMove* playerphysics; std::map handleToMesh; PhysicsSystem (const PhysicsSystem&); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 47751acb39..1966603fee 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -8,6 +8,7 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index ad6ad1559e..2333a95ab0 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -3,7 +3,7 @@ #include "../mwrender/renderingmanager.hpp" -#include "physicssystem.hpp" +#include "ptr.hpp" #include "globals.hpp" namespace Ogre @@ -34,9 +34,9 @@ namespace MWRender namespace MWWorld { + class PhysicsSystem; class Player; class CellStore; - class Ptr; class Scene { From ca6f8b6d88f8abf2f58386691eb3d0e86b3a3769 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 13:18:16 -0800 Subject: [PATCH 0287/1483] Reorganize a bit of code in the movement solver --- apps/openmw/mwworld/physicssystem.cpp | 70 ++++++++++++--------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 6c41d56e65..b6d507da92 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -27,6 +27,8 @@ namespace MWWorld static const float sMaxSlope = 60.0f; static const float sStepSize = 9.0f; + // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + static const int sMaxIterations = 50; class MovementSolver { @@ -85,7 +87,7 @@ namespace MWWorld } public: - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { const ESM::Position &refpos = ptr.getRefData().getPosition(); @@ -103,55 +105,44 @@ namespace MWWorld } traceResults trace; //no initialization needed - int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - - if(!gravity) - { - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * - movement; - } - else - { - movement = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * - movement; - } - - Ogre::Vector3 horizontalVelocity = movement/time; - float verticalVelocity = (gravity ? physicActor->getVerticalForce() : - horizontalVelocity.z); - Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps - Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); - float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); - Ogre::Vector3 newPosition = position; + Ogre::Vector3 velocity; + if(!gravity) + { + velocity = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement / time; + } + else + { + velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * + movement / time; + velocity.z = physicActor->getVerticalForce(); + } + + // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(velocity); if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f) + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) { - if(getSlope(trace.planenormal) > sMaxSlope) - { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); - } + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); } } + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + int iterations = 0; do { // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); @@ -186,10 +177,9 @@ namespace MWWorld lastNormal = currentNormal; iterations++; - } while(iterations < maxIterations && remainingTime != 0.0f); + } while(iterations < sMaxIterations && remainingTime > 0.0f); - verticalVelocity = clippedVelocity.z; - physicActor->setVerticalForce(verticalVelocity - time*400.0f); + physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; } From cbdd459500cd2c164f633e11d2173d21e9ec4cb7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 15:48:41 -0800 Subject: [PATCH 0288/1483] Remove unneeded playerMove from PhysicActor --- apps/openmw/mwworld/physicssystem.cpp | 10 +--- libs/openengine/bullet/physic.cpp | 71 +-------------------------- libs/openengine/bullet/physic.hpp | 35 +------------ 3 files changed, 3 insertions(+), 113 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b6d507da92..cb8eb2a025 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -267,8 +267,7 @@ namespace MWWorld void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) { - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - it->second->setCurrentWater(hasWater, waterHeight); + // TODO: store and use } btVector3 PhysicsSystem::getRayPoint(float extent) @@ -405,13 +404,6 @@ namespace MWWorld mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); } } - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - if (handle != "player") - act->setPosition(position); - } } void PhysicsSystem::rotateObject (const Ptr& ptr) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 95313cdba4..06f9523050 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -34,14 +34,6 @@ namespace Physic Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map - pmove = new playerMove; - pmove->mEngine = mEngine; - btBoxShape* box = static_cast (mBody->getCollisionShape()); - if(box != NULL){ - btVector3 size = box->getHalfExtentsWithMargin(); - Ogre::Vector3 halfExtents = Ogre::Vector3(size.getX(), size.getY(), size.getZ()); - pmove->ps.halfExtents = halfExtents; - } } PhysicActor::~PhysicActor() @@ -50,38 +42,11 @@ namespace Physic mEngine->dynamicsWorld->removeRigidBody(mBody); delete mBody; } - delete pmove; - } - - void PhysicActor::setCurrentWater(bool hasWater, int waterHeight){ - pmove->hasWater = hasWater; - if(hasWater){ - pmove->waterHeight = waterHeight; - } - } - - void PhysicActor::setGravity(float gravity) - { - pmove->ps.gravity = gravity; - } - - void PhysicActor::setSpeed(float speed) - { - pmove->ps.speed = speed; } void PhysicActor::enableCollisions(bool collision) { collisionMode = collision; - if(collisionMode) - pmove->ps.move_type=PM_NORMAL; - else - pmove->ps.move_type=PM_NOCLIP; - } - - void PhysicActor::setJumpVelocity(float velocity) - { - pmove->ps.jump_velocity = velocity; } bool PhysicActor::getCollisionMode() @@ -89,23 +54,8 @@ namespace Physic return collisionMode; } - void PhysicActor::setMovement(signed char rightmove, signed char forwardmove, signed char upmove) - { - playerMove::playercmd& pm_ref = pmove->cmd; - pm_ref.rightmove = rightmove; - pm_ref.forwardmove = forwardmove; - pm_ref.upmove = upmove; - } - void PhysicActor::setPmoveViewAngles(float pitch, float yaw, float roll){ - pmove->ps.viewangles.x = pitch; - pmove->ps.viewangles.y = yaw; - pmove->ps.viewangles.z = roll; - } - - - - void PhysicActor::setRotation(const Ogre::Quaternion quat) + void PhysicActor::setRotation(const Ogre::Quaternion &quat) { if(!quat.equals(getRotation(), Ogre::Radian(0))){ mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); @@ -128,13 +78,6 @@ namespace Physic return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()); } - void PhysicActor::setPosition(const Ogre::Vector3 pos) - { - mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); - btVector3 vec = mBody->getWorldTransform().getOrigin(); - pmove->ps.origin = Ogre::Vector3(vec.getX(), vec.getY(), vec.getZ()); - } - void PhysicActor::setScale(float scale){ Ogre::Vector3 position = getPosition(); Ogre::Quaternion rotation = getRotation(); @@ -148,12 +91,6 @@ namespace Physic //Create the newly scaled rigid body mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation); mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map - btBoxShape* box = static_cast (mBody->getCollisionShape()); - if(box != NULL){ - btVector3 size = box->getHalfExtentsWithMargin(); - Ogre::Vector3 halfExtents = Ogre::Vector3(size.getX(), size.getY(), size.getZ()); - pmove->ps.halfExtents = halfExtents; - } } Ogre::Vector3 PhysicActor::getHalfExtents() const @@ -190,12 +127,6 @@ namespace Physic return collisionMode && onGround; } - void PhysicActor::runPmove(){ - Pmove(pmove); - Ogre::Vector3 newpos = pmove->ps.origin; - mBody->getWorldTransform().setOrigin(btVector3(newpos.x, newpos.y, newpos.z)); - } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 4bc926b8ab..aa832ddcc0 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -18,7 +18,6 @@ class btSequentialImpulseConstraintSolver; class btCollisionDispatcher; class btDiscreteDynamicsWorld; class btHeightfieldTerrainShape; -struct playerMove; namespace BtOgre { @@ -65,25 +64,12 @@ namespace Physic ~PhysicActor(); - void setCurrentWater(bool hasWater, int waterHeight); - - /** - * This function sets the movement keys for pmove - */ - void setMovement(signed char rightmove, signed char forwardmove, signed char upmove); - /** * This adjusts the rotation of a PhysicActor * If we have any problems with this (getting stuck in pmove) we should change it * from setting the visual orientation to setting the orientation of the rigid body directly. */ - void setRotation(const Ogre::Quaternion quat); - - void setGravity(float gravity); - - void setSpeed(float speed); - - void setJumpVelocity(float velocity); + void setRotation(const Ogre::Quaternion &quat); void enableCollisions(bool collision); @@ -100,18 +86,6 @@ namespace Physic */ Ogre::Quaternion getRotation(); - /** - * Sets the position of mBody from a visual position input. - * For most cases this should not be used. We should instead let pmove move the PhysicActor around for us - */ - void setPosition(const Ogre::Vector3 pos); - - /** - * Sets the view angles for pmove directly. - * Remember, add 90 for yaw. Set roll to 0. - */ - void setPmoveViewAngles(float pitch, float yaw, float roll); - /** * Sets the scale of the PhysicActor */ @@ -136,11 +110,6 @@ namespace Physic bool getOnGround() const; - /** - * Runs pmove for this PhysicActor - */ - void runPmove(); - //HACK: in Visual Studio 2010 and presumably above, this structures alignment // must be 16, but the built in operator new & delete don't properly // perform this alignment. @@ -161,8 +130,6 @@ namespace Physic std::string mMesh; PhysicEngine* mEngine; std::string mName; - playerMove* pmove; - }; /** From d47d2216f2c9494d6a1b4e48df658485ea568bdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 16:18:29 -0800 Subject: [PATCH 0289/1483] Use some const references where appropriate --- apps/openmw/mwworld/physicssystem.cpp | 6 ++-- libs/openengine/bullet/physic.cpp | 42 +++++++++++++++------------ libs/openengine/bullet/physic.hpp | 27 ++++++++--------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index cb8eb2a025..8bf852f422 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -409,8 +409,8 @@ namespace MWWorld void PhysicsSystem::rotateObject (const Ptr& ptr) { Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); - Ogre::Quaternion rotation = node->getOrientation(); + const std::string &handle = node->getName(); + const Ogre::Quaternion &rotation = node->getOrientation(); if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { //Needs to be changed @@ -428,7 +428,7 @@ namespace MWWorld void PhysicsSystem::scaleObject (const Ptr& ptr) { Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); + const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { removeObject(handle); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 06f9523050..2b26c3a487 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -27,8 +27,9 @@ namespace Physic COL_RAYCASTING = BIT(3) }; - PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) + : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) + , mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -38,7 +39,8 @@ namespace Physic PhysicActor::~PhysicActor() { - if(mBody){ + if(mBody) + { mEngine->dynamicsWorld->removeRigidBody(mBody); delete mBody; } @@ -321,18 +323,21 @@ namespace Physic mHeightFieldMap.erase(name); } - void PhysicEngine::adjustRigidBody(RigidBody* body, Ogre::Vector3 position, Ogre::Quaternion rotation, - Ogre::Vector3 scaledBoxTranslation, Ogre::Quaternion boxRotation){ + void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + const Ogre::Vector3 &scaledBoxTranslation, const Ogre::Quaternion &boxRotation) + { btTransform tr; - rotation = rotation * boxRotation; - Ogre::Vector3 transrot = rotation * scaledBoxTranslation; + Ogre::Quaternion boxrot = rotation * boxRotation; + Ogre::Vector3 transrot = boxrot * scaledBoxTranslation; Ogre::Vector3 newPosition = transrot + position; - + tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z)); - tr.setRotation(btQuaternion(rotation.x,rotation.y,rotation.z,rotation.w)); + tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w)); body->setWorldTransform(tr); } - void PhysicEngine::boxAdjustExternal(std::string mesh, RigidBody* body, float scale, Ogre::Vector3 position, Ogre::Quaternion rotation){ + void PhysicEngine::boxAdjustExternal(const std::string &mesh, RigidBody* body, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) + { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; //std::cout << "The string" << outputstring << "\n"; @@ -345,7 +350,8 @@ namespace Physic adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); } - RigidBody* PhysicEngine::createAndAdjustRigidBody(std::string mesh,std::string name,float scale, Ogre::Vector3 position, Ogre::Quaternion rotation, + RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation) { std::string sid = (boost::format("%07.3f") % scale).str(); @@ -406,7 +412,7 @@ namespace Physic } } - void PhysicEngine::removeRigidBody(std::string name) + void PhysicEngine::removeRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -426,7 +432,7 @@ namespace Physic } } - void PhysicEngine::deleteRigidBody(std::string name) + void PhysicEngine::deleteRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -446,7 +452,7 @@ namespace Physic } } - RigidBody* PhysicEngine::getRigidBody(std::string name) + RigidBody* PhysicEngine::getRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -469,8 +475,8 @@ namespace Physic } } - void PhysicEngine::addCharacter(std::string name, std::string mesh, - Ogre::Vector3 position, float scale, Ogre::Quaternion rotation) + void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh, + const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation) { // Remove character with given name, so we don't make memory // leak when character would be added twice @@ -483,7 +489,7 @@ namespace Physic PhysicActorMap[name] = newActor; } - void PhysicEngine::removeCharacter(std::string name) + void PhysicEngine::removeCharacter(const std::string &name) { //std::cout << "remove"; PhysicActorContainer::iterator it = PhysicActorMap.find(name); @@ -499,7 +505,7 @@ namespace Physic } } - PhysicActor* PhysicEngine::getCharacter(std::string name) + PhysicActor* PhysicEngine::getCharacter(const std::string &name) { PhysicActorContainer::iterator it = PhysicActorMap.find(name); if (it != PhysicActorMap.end() ) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index aa832ddcc0..1a28023a90 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -60,7 +60,7 @@ namespace Physic class PhysicActor { public: - PhysicActor(std::string name, std::string mesh, PhysicEngine *engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale); + PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale); ~PhysicActor(); @@ -178,19 +178,21 @@ namespace Physic * Creates a RigidBody. It does not add it to the simulation. * After created, the body is set to the correct rotation, position, and scale */ - RigidBody* createAndAdjustRigidBody(std::string mesh,std::string name,float scale, Ogre::Vector3 position, Ogre::Quaternion rotation, + RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0); /** * Adjusts a rigid body to the right position and rotation */ - void adjustRigidBody(RigidBody* body, Ogre::Vector3 position, Ogre::Quaternion rotation, - Ogre::Vector3 scaledBoxTranslation = Ogre::Vector3::ZERO, Ogre::Quaternion boxRotation = Ogre::Quaternion::IDENTITY); + void adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + const Ogre::Vector3 &scaledBoxTranslation = Ogre::Vector3::ZERO, + const Ogre::Quaternion &boxRotation = Ogre::Quaternion::IDENTITY); /** Mainly used to (but not limited to) adjust rigid bodies based on box shapes to the right position and rotation. */ - void boxAdjustExternal(std::string mesh, RigidBody* body, float scale, Ogre::Vector3 position, Ogre::Quaternion rotation); + void boxAdjustExternal(const std::string &mesh, RigidBody* body, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); /** * Add a HeightField to the simulation */ @@ -211,35 +213,35 @@ namespace Physic /** * Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap. */ - void removeRigidBody(std::string name); + void removeRigidBody(const std::string &name); /** * Delete a RigidBody, and remove it from RigidBodyMap. */ - void deleteRigidBody(std::string name); + void deleteRigidBody(const std::string &name); /** * Return a pointer to a given rigid body. * TODO:check if exist */ - RigidBody* getRigidBody(std::string name); + RigidBody* getRigidBody(const std::string &name); /** * Create and add a character to the scene, and add it to the ActorMap. */ - void addCharacter(std::string name, std::string mesh, - Ogre::Vector3 position, float scale, Ogre::Quaternion rotation); + void addCharacter(const std::string &name, const std::string &mesh, + const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation); /** * Remove a character from the scene. TODO:delete it! for now, a small memory leak^^ done? */ - void removeCharacter(std::string name); + void removeCharacter(const std::string &name); /** * Return a pointer to a character * TODO:check if the actor exist... */ - PhysicActor* getCharacter(std::string name); + PhysicActor* getCharacter(const std::string &name); /** * This step the simulation of a given time. @@ -307,7 +309,6 @@ namespace Physic BtOgre::DebugDrawer* mDebugDrawer; bool isDebugCreated; bool mDebugActive; - }; From f5afa43db5037f4e8f4343db6ef933c7bb7279a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 17:45:41 -0800 Subject: [PATCH 0290/1483] Remove an unneeded parameter --- apps/openmw/mwworld/physicssystem.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 8bf852f422..a5dd7f3693 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -56,20 +56,17 @@ namespace MWWorld return false; } - static void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, - const float overbounce) + static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce) { //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. - float backoff; - - backoff = in.dotProduct(normal); + float backoff = inout.dotProduct(normal); if(backoff < 0.0f) backoff *= overbounce; else backoff /= overbounce; - out = in - (normal*backoff); + inout -= normal*backoff; } static void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) @@ -134,7 +131,7 @@ namespace MWWorld if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) { // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } } @@ -171,7 +168,7 @@ namespace MWWorld // std::cout<< "stepped" < Date: Fri, 8 Feb 2013 09:58:19 +0100 Subject: [PATCH 0291/1483] basic gmst support --- apps/opencs/model/world/data.cpp | 7 +++++++ apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 6 +++--- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 3 +++ components/esm/loadgmst.cpp | 23 ++++++++++++++++++++++- components/esm/loadgmst.hpp | 11 ++++++++--- 9 files changed, 58 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 9b89533a64..89c19f0328 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -28,7 +28,13 @@ CSMWorld::Data::Data() mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); mGlobals.addColumn (new FloatValueColumn); + mGmsts.addColumn (new StringIdColumn); + mGmsts.addColumn (new RecordStateColumn); + mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); + ///< \todo add type and value + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); + addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); } CSMWorld::Data::~Data() @@ -78,6 +84,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) switch (n.val) { case ESM::REC_GLOB: mGlobals.load (reader, base); break; + case ESM::REC_GMST: mGmsts.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8a6cd736b4..519817a3b4 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -18,6 +19,7 @@ namespace CSMWorld class Data { IdCollection mGlobals; + IdCollection mGmsts; std::vector mModels; std::map mModelIndex; diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index d8775643ac..c006852bc6 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -18,6 +18,7 @@ namespace { { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -25,6 +26,7 @@ namespace static const TypeData sIdArg[] = { { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 4a73feb12c..9ff7d17b18 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -33,12 +33,12 @@ namespace CSMWorld enum Type { Type_None, - Type_Globals, - Type_Global, + Type_VerificationResults, + Type_Gmsts, + Type_Gmst - Type_VerificationResults }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index f5cc3d85b0..4fd03041f8 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -71,6 +71,10 @@ void CSVDoc::View::setupWorldMenu() connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView())); world->addAction (globals); + QAction *gmsts = new QAction (tr ("Game settings"), this); + connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView())); + world->addAction (gmsts); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -217,4 +221,9 @@ void CSVDoc::View::verify() void CSVDoc::View::addGlobalsSubView() { addSubView (CSMWorld::UniversalId::Type_Globals); +} + +void CSVDoc::View::addGmstsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Gmsts); } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 05d7210dce..6bdd54e6bf 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -99,6 +99,8 @@ namespace CSVDoc void verify(); void addGlobalsSubView(); + + void addGmstsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 080a175ea5..351007ded5 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -11,6 +11,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Gmsts, + new CSVDoc::SubViewFactoryWithCreateFlag (false)); + manager.add (CSMWorld::UniversalId::Type_Global, new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index a73095a66a..e9852ec076 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -76,8 +76,29 @@ std::string GameSetting::getString() const { if (mType==VT_String) return mStr; - + throw std::runtime_error ("GMST " + mId + " is not a string"); } + void GameSetting::blank() + { + mStr.clear(); + mI = 0; + mF = 0; + mType = VT_Float; + } + + bool operator== (const GameSetting& left, const GameSetting& right) + { + if (left.mType!=right.mType) + return false; + + switch (left.mType) + { + case VT_Float: return left.mF==right.mF; + case VT_Int: return left.mI==right.mI; + case VT_String: return left.mStr==right.mStr; + default: return false; + } + } } diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index ab9a9551e5..f7aec5c76c 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -26,17 +26,22 @@ struct GameSetting VarType mType; void load(ESMReader &esm); - + int getInt() const; ///< Throws an exception if GMST is not of type int or float. - + float getFloat() const; ///< Throws an exception if GMST is not of type int or float. - + std::string getString() const; ///< Throwns an exception if GMST is not of type string. void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID). }; + + bool operator== (const GameSetting& left, const GameSetting& right); } #endif From cce2d63433a137fa47856670bc433291e4321852 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 8 Feb 2013 12:20:03 +0100 Subject: [PATCH 0292/1483] added type column to gmst table --- apps/opencs/model/world/columns.hpp | 23 +++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1e2de92658..7473876763 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -91,6 +91,29 @@ namespace CSMWorld return false; } }; + + template + struct VarTypeColumn : public Column + { + VarTypeColumn() : Column ("Type", ColumnBase::Display_Float) {} + + virtual QVariant get (const Record& record) const + { + return static_cast (record.get().mType); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT base = record.getBase(); + base.mType = static_cast (data.toInt()); + record.setModified (base); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 89c19f0328..69e62db018 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -31,7 +31,8 @@ CSMWorld::Data::Data() mGmsts.addColumn (new StringIdColumn); mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); - ///< \todo add type and value + mGmsts.addColumn (new VarTypeColumn); + ///< \todo add value addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 828695f295e07cd9ece9cbc6333a83c49cf033b3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 8 Feb 2013 14:48:38 +0100 Subject: [PATCH 0293/1483] added value column to gmst table --- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 41 +++++++++++++++++++++- apps/opencs/model/world/data.cpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 4 +++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 38b73ee3f5..f1871a6a94 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -28,7 +28,8 @@ namespace CSMWorld { Display_String, Display_Integer, - Display_Float + Display_Float, + Display_Var }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7473876763..fb94cbf591 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -95,7 +95,7 @@ namespace CSMWorld template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_Float) {} + VarTypeColumn() : Column ("Type", ColumnBase::Display_Integer) {} virtual QVariant get (const Record& record) const { @@ -114,6 +114,45 @@ namespace CSMWorld return true; } }; + + template + struct VarValueColumn : public Column + { + VarValueColumn() : Column ("Value", ColumnBase::Display_Var) {} + + virtual QVariant get (const Record& record) const + { + switch (record.get().mType) + { + case ESM::VT_String: return record.get().mStr.c_str(); break; + case ESM::VT_Int: return record.get().mI; break; + case ESM::VT_Float: return record.get().mF; break; + + default: return QVariant(); + } + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT base = record.getBase(); + + switch (record.get().mType) + { + case ESM::VT_String: base.mStr = data.toString().toUtf8().constData(); break; + case ESM::VT_Int: base.mI = data.toInt(); break; + case ESM::VT_Float: base.mF = data.toFloat(); break; + + default: break; + } + + record.setModified (base); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 69e62db018..f120c75f10 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -32,7 +32,7 @@ CSMWorld::Data::Data() mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); mGmsts.addColumn (new VarTypeColumn); - ///< \todo add value + mGmsts.addColumn (new VarValueColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 2bf6577b11..e16de99eff 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -64,6 +64,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM /// \todo configure widget properly (range, format?) layout->addWidget (widget = new QDoubleSpinBox, i, 1); break; + + default: break; // silence warnings for other times for now } } else @@ -76,6 +78,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM layout->addWidget (widget = new QLabel, i, 1); break; + + default: break; // silence warnings for other times for now } } From 735c1ec2ae658a490d7bf5a3035bdde28ad19cb6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 8 Feb 2013 13:12:34 -0800 Subject: [PATCH 0294/1483] Cleanup trace.cpp/h --- libs/openengine/bullet/trace.cpp | 256 +++++++++++-------------------- libs/openengine/bullet/trace.h | 51 +----- 2 files changed, 99 insertions(+), 208 deletions(-) diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 847059530c..138411e11b 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -3,190 +3,116 @@ #include +#include +#include + #include "physic.hpp" #include "pmove.h" -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object +enum traceWorldType { - //static float lastyaw = 0.0f; - //static float lastpitch = 0.0f; - //if (!traceobj) - // return; - - //if (!traceobj->incellptr) - // return; - - - const Ogre::Vector3 rayDir = end - start; - - - - - - - - NewPhysTraceResults out; - //std::cout << "Starting trace\n"; - //Ogre::Vector3 startReplace = Ogre::Vector3(650,950, 45); - //Ogre::Vector3 endReplace = startReplace; - //endReplace.z -= .25; - - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), isInterior, enginePass); - - if (out.fraction < 0.001f) - results->startsolid = true; - else - results->startsolid = false; - - - //results->allsolid = out.startSolid; - - // If outside and underground, we're solid - /*if (isInterior) - { - const Ogre::Vector3 height = GetGroundPosition(start, CellCoords(traceCell->data->gridX, traceCell->data->gridY) ); - if (start.yPos - height.yPos < (-2.0f * BBHalfExtents.yPos) ) - { - results->allsolid = true; - } - else - results->allsolid = false; - }*/ - - // If inside and out of the tree, we're solid - //else - //{ - results->allsolid = out.startSolid; - //std::cout << "allsolid" << results->allsolid << "\n"; - //} - - if (!hasHit) - { - results->endpos = end; - results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - results->entityNum = ENTITYNUM_NONE; - results->fraction = 1.0f; - } - else - { - results->fraction = out.fraction; - results->planenormal = out.hitNormal; - results->endpos = rayDir * results->fraction + start; - results->entityNum = ENTITYNUM_WORLD; - /*bprintf("Start: (%f, %f, %f) End: (%f, %f, %f) TraceDir: (%f, %f, %f) HitNormal: (%f, %f, %f) Fraction: %f Hitpos: (%f, %f, %f) CompensatedHitpos: (%f, %f, %f)\n", - start.xPos, start.yPos, start.zPos, - end.xPos, end.yPos, end.zPos, - rayDir.xPos, rayDir.yPos, rayDir.zPos, - results->planenormal.xPos, results->planenormal.yPos, results->planenormal.zPos, results->fraction, - out.endPos.xPos, out.endPos.yPos, out.endPos.zPos, - results->endpos.xPos, results->endpos.yPos, results->endpos.zPos);*/ - } -} + collisionWorldTrace = 1, + pickWorldTrace = 2, + bothWorldTrace = collisionWorldTrace | pickWorldTrace +}; +enum collaborativePhysicsType +{ + No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass) + Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics) + Only_Pickup = 2, // This object only has pickup physics but no collision physics (example: items dropped on the ground) + Both_Physics = 3 // This object has both kinds of physics (example: activators) +}; +struct NewPhysTraceResults +{ + Ogre::Vector3 endPos; + Ogre::Vector3 hitNormal; + float fraction; + bool startSolid; + //const Object* hitObj; +}; template -const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) +static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, + const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, + OEngine::Physic::PhysicEngine* enginePass) { - //if (!traceobj->incellptr) - // return false; - //if(enginePass->dynamicsWorld->getCollisionObjectArray().at(60)->getCollisionShape()->isConvex()) - // std::cout << "It's convex\n"; - - - - const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); - const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); - const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z + const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); + const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); + const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); - //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); - const btTransform from(btrot, btstart); - const btTransform to(btrot, btend); + //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); + const btTransform from(btrot, btstart); + const btTransform to(btrot, btend); - // warning: unused variable ... - /* - float x = from.getOrigin().getX(); - float y = from.getOrigin().getY(); - float z = from.getOrigin().getZ(); - float x2 = to.getOrigin().getX(); - float y2 = to.getOrigin().getY(); - float z2 = to.getOrigin().getZ(); - */ - - //std::cout << "BtFrom: " << x << "," << y << "," << z << "\n"; - //std::cout << "BtTo: " << x2 << "," << y2 << "," << z2 << "\n"; - //std::cout << "BtTo: " << to.getOrigin().getX() << "," << to.getOrigin().getY() << "," << to.getOrigin().getZ() << "\n"; + btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); + newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; - btCollisionWorld::ClosestConvexResultCallback - newTraceCallback(btstart, btend); + enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); - newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; - - - enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); - //newTraceCallback. - - - //std::cout << "NUM: " << enginePass->dynamicsWorld->getNumCollisionObjects() << "\n"; + // Copy the hit data over to our trace results struct: + out->fraction = newTraceCallback.m_closestHitFraction; - // Copy the hit data over to our trace results struct: - out->fraction = newTraceCallback.m_closestHitFraction; + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + out->hitNormal.x = tracehitnormal.x(); + out->hitNormal.y = tracehitnormal.y(); + out->hitNormal.z = tracehitnormal.z(); - Ogre::Vector3& outhitnormal = out->hitNormal; - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; + out->endPos.x = tracehitpos.x(); + out->endPos.y = tracehitpos.y(); + out->endPos.z = tracehitpos.z(); - outhitnormal.x = tracehitnormal.x(); - outhitnormal.y = tracehitnormal.y(); - outhitnormal.z = tracehitnormal.z(); - - Ogre::Vector3& outhitpos = out->endPos; - const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; - - outhitpos.x = tracehitpos.x(); - outhitpos.y = tracehitpos.y(); - outhitpos.z= tracehitpos.z(); - - // StartSolid test: - { - out->startSolid = false; - //btCollisionObject collision; - //collision.setCollisionShape(const_cast(&newshape) ); - - //CustomContactCallback crb; - - //world.world->contactTest(&collision, crb); - //out->startSolid = crb.hit; - - // If outside and underground, we're solid - if (!isInterior) //Check if we are interior - { - } - - // If inside and out of the tree, we're solid - else - { - btVector3 aabbMin, aabbMax; - enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); - //std::cout << "AABBMIN" << aabbMin.getX() <<"," <startSolid = false; + if(isInterior) + { + // If inside and out of the tree, we're solid + btVector3 aabbMin, aabbMax; + enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); + btVector3 point(start.x, start.y, start.z); + if(!TestPointAgainstAabb2(aabbMin, aabbMax, point)) + { + //We're solid + //THIS NEEDS TO BE TURNED OFF IF WE WANT FALLING IN EXTERIORS TO WORK CORRECTLY!!!!!!! //out->startSolid = true; - } - } - } + } + } + } - const bool hasHit = newTraceCallback.hasHit(); - - - - - return hasHit; + return newTraceCallback.hasHit(); +} + + +void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object +{ + NewPhysTraceResults out; + const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, + Ogre::Vector3(0.0f, 0.0f, 0.0f), + isInterior, enginePass); + if (out.fraction < 0.001f) + results->startsolid = true; + else + results->startsolid = false; + results->allsolid = out.startSolid; + + if(!hasHit) + { + results->endpos = end; + results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); + results->entityNum = ENTITYNUM_NONE; + results->fraction = 1.0f; + } + else + { + results->fraction = out.fraction; + results->planenormal = out.hitNormal; + results->endpos = (end-start)*results->fraction + start; + results->entityNum = ENTITYNUM_WORLD; + } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 462d062ebe..94708d403f 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -1,10 +1,6 @@ #ifndef OENGINE_BULLET_TRACE_H #define OENGINE_BULLET_TRACE_H - -#include -#include - #include @@ -17,52 +13,21 @@ namespace OEngine } -enum traceWorldType -{ - collisionWorldTrace = 1, - pickWorldTrace = 2, - bothWorldTrace = collisionWorldTrace | pickWorldTrace -}; - -enum collaborativePhysicsType -{ - No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass) - Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics) - Only_Pickup = 2, // This object only has pickup physics but no collision physics (example: items dropped on the ground) - Both_Physics = 3 // This object has both kinds of physics (example: activators) -}; - -struct NewPhysTraceResults -{ - Ogre::Vector3 endPos; - Ogre::Vector3 hitNormal; - float fraction; - bool startSolid; - //const Object* hitObj; -}; struct traceResults { - Ogre::Vector3 endpos; - Ogre::Vector3 planenormal; + Ogre::Vector3 endpos; + Ogre::Vector3 planenormal; - float fraction; + float fraction; - int surfaceFlags; - int contents; - int entityNum; + int surfaceFlags; + int contents; + int entityNum; - bool allsolid; - bool startsolid; + bool allsolid; + bool startsolid; }; - - -template -const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -//template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -//template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); - void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); - #endif From eefbdde6de862e15f27ae90c410687eb8a988729 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 9 Feb 2013 13:00:57 +0100 Subject: [PATCH 0295/1483] - For pull request: remove all instances of maps used to track refnumbers. - new file: apps/openmw/mwworld/store.cpp, had to move reference merging method out of the header file to prevent three-way recursion/unresolved forward references in custom compare operators. --- apps/openmw/main.cpp | 6 +- apps/openmw/mwworld/cells.cpp | 12 ++-- apps/openmw/mwworld/cellstore.cpp | 42 ++++++++++++- apps/openmw/mwworld/cellstore.hpp | 84 ++++---------------------- apps/openmw/mwworld/containerstore.cpp | 28 ++++----- apps/openmw/mwworld/containerstore.hpp | 72 +++++++++++----------- apps/openmw/mwworld/localscripts.cpp | 6 +- apps/openmw/mwworld/scene.cpp | 6 +- apps/openmw/mwworld/store.cpp | 65 ++++++++++++++++++++ apps/openmw/mwworld/store.hpp | 64 +++----------------- apps/openmw/mwworld/worldimp.cpp | 14 ++--- components/esm/loadcell.cpp | 26 +++++--- components/esm/loadcell.hpp | 33 +++++----- 13 files changed, 233 insertions(+), 225 deletions(-) create mode 100644 apps/openmw/mwworld/store.cpp diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 1be669ae07..86978c9b11 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -213,8 +213,10 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat StringsVector plugin = variables["plugin"].as(); // Removed check for 255 files, which would be the hard-coded limit in Morrowind. - // I'll keep the following variable in, maybe we can use it for somethng different. - int cnt = master.size() + plugin.size(); + // I'll keep the following variable in, maybe we can use it for something different. + // Say, a feedback like "loading file x/cnt". + // Commenting this out for now to silence compiler warning. + //int cnt = master.size() + plugin.size(); // Prepare loading master/plugin files (i.e. send filenames to engine) for (std::vector::size_type i = 0; i < master.size(); i++) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 7e421dc559..59c62e37d6 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -42,30 +42,30 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) cellStore.mContainers.mList.begin()); iter!=cellStore.mContainers.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.mCreatures.mList.begin()); iter!=cellStore.mCreatures.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.mNpcs.mList.begin()); iter!=cellStore.mNpcs.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 7f1cdc469e..baf4fea324 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -10,6 +10,41 @@ namespace MWWorld { + + template + void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) + { + // Get existing reference, in case we need to overwrite it. + typename std::list::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefnum); + + // Skip this when reference was deleted. + // TODO: Support respawning references, in this case, we need to track it somehow. + if (ref.mDeleted) { + mList.erase(iter); + return; + } + + // for throwing exception on unhandled record type + const MWWorld::Store &store = esmStore.get(); + const X *ptr = store.search(ref.mRefID); + + /// \note no longer redundant - changed to Store::search(), don't throw + /// an exception on miss, try to continue (that's how MW does it, anyway) + if (ptr == NULL) { + std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl; + } else { + if (iter != mList.end()) + *iter = LiveRef(ref, ptr); + else + mList.push_back(LiveRef(ref, ptr)); + } + } + + template bool operator==(const LiveCellRef& ref, int pRefnum) + { + return (ref.mRef.mRefnum == pRefnum); + } + CellStore::CellStore (const ESM::Cell *cell) : mCell (cell), mState (State_Unloaded) { @@ -95,7 +130,8 @@ namespace MWWorld { // Don't load reference if it was moved to a different cell. std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID); - if (mCell->mMovedRefs.find(ref.mRefnum) != mCell->mMovedRefs.end()) { + ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum); + if (iter != mCell->mMovedRefs.end()) { continue; } int rec = store.find(ref.mRefID); @@ -141,8 +177,8 @@ namespace MWWorld for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); it++) { // Doesn't seem to work in one line... huh? Too sleepy to check... - //const ESM::CellRef &ref0 = it->second; - ESM::CellRef &ref = const_cast(it->second); + ESM::CellRef &ref = const_cast(*it); + //ESM::CellRef &ref = const_cast(it->second); std::string lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cbaf56458c..c182f196bc 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,11 +9,12 @@ #include "refdata.hpp" #include "esmstore.hpp" +struct C; namespace MWWorld { class Ptr; class ESMStore; - + /// A reference to one object (of any type) in a cell. /// /// Constructing this with a CellRef instance in the constructor means that @@ -42,88 +43,25 @@ namespace MWWorld /// runtime-data RefData mData; }; + + template bool operator==(const LiveCellRef& ref, int pRefnum); /// A list of cell references template struct CellRefList { typedef LiveCellRef LiveRef; - typedef std::map List; + typedef std::list List; List mList; // Search for the given reference in the given reclist from // ESMStore. Insert the reference into the list if a match is // found. If not, throw an exception. - /// Searches for reference of appropriate type in given ESMStore. - /// If reference exists, loads it into container, throws an exception - /// on miss - void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) - { - // Skip this when reference was deleted. - // TODO: Support respawning references, in this case, we need to track it somehow. - if (ref.mDeleted) { - mList.erase(ref.mRefnum); - return; - } - - // for throwing exception on unhandled record type - const MWWorld::Store &store = esmStore.get(); - const X *ptr = store.search(ref.mRefID); - - /// \note no longer redundant - changed to Store::search(), don't throw - /// an exception on miss, try to continue (that's how MW does it, anyway) - if (ptr == NULL) { - std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl; - } else - mList[ref.mRefnum] = LiveRef(ref, ptr); - } - - LiveRef *find (const std::string& name) - { - for (typename std::map::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - { - if (iter->second.mData.getCount() > 0 && iter->second.mRef.mRefID == name) - return &iter->second; - } - - return 0; - } - - LiveRef &insert(const LiveRef &item) { - mList[item.mRef.mRefnum] = item; - return mList[item.mRef.mRefnum]; - } - }; - - /// A list of container references. These references do not track their mRefnumber. - /// Otherwise, taking 1 of 20 instances of an object would produce multiple objects - /// with the same reference. - /// Unfortunately, this also means that we need a different STL container. - /// (cells use CellRefList, where refs can be located according to their refnumner, - /// which uses a map; container items do not make use of the refnumber, so we - /// can't use a map with refnumber keys.) - template - struct ContainerRefList - { - typedef LiveCellRef LiveRef; - typedef std::list List; - List mList; - - /// Searches for reference of appropriate type in given ESMStore. - /// If reference exists, loads it into container, throws an exception - /// on miss - void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) - { - // for throwing exception on unhandled record type - const MWWorld::Store &store = esmStore.get(); - const X *ptr = store.find(ref.mRefID); - - /// \note redundant because Store::find() throws exception on miss - if (ptr == NULL) { - throw std::runtime_error("Error resolving cell reference " + ref.mRefID); - } - mList.push_back(LiveRef(ref, ptr)); - } + // Moved to cpp file, as we require a custom compare operator for it, + // and the build will fail with an ugly three-way cyclic header dependence + // so we need to pass the instantiation of the method to the lnker, when + // all methods are known. + void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore); LiveRef *find (const std::string& name) { @@ -236,7 +174,7 @@ namespace MWWorld { for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) - if (!functor (iter->second.mRef, iter->second.mData)) + if (!functor (iter->mRef, iter->mData)) return false; return true; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 36addee862..bca4073b52 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -21,11 +21,11 @@ namespace { template - float getTotalWeight (const MWWorld::ContainerRefList& cellRefList) + float getTotalWeight (const MWWorld::CellRefList& cellRefList) { float sum = 0; - for (typename MWWorld::ContainerRefList::List::const_iterator iter ( + for (typename MWWorld::CellRefList::List::const_iterator iter ( cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) @@ -300,29 +300,29 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor ++*this; } -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Potion), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mPotion(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Apparatus), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mApparatus(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Armor), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mArmor(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Book), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mBook(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Clothing), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mClothing(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Probe), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mProbe(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Repair), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mRepair(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Weapon), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mWeapon(iterator){} void MWWorld::ContainerStoreIterator::incType() diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 63695c0df5..e4f75d5478 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -37,18 +37,18 @@ namespace MWWorld private: - MWWorld::ContainerRefList potions; - MWWorld::ContainerRefList appas; - MWWorld::ContainerRefList armors; - MWWorld::ContainerRefList books; - MWWorld::ContainerRefList clothes; - MWWorld::ContainerRefList ingreds; - MWWorld::ContainerRefList lights; - MWWorld::ContainerRefList lockpicks; - MWWorld::ContainerRefList miscItems; - MWWorld::ContainerRefList probes; - MWWorld::ContainerRefList repairs; - MWWorld::ContainerRefList weapons; + MWWorld::CellRefList potions; + MWWorld::CellRefList appas; + MWWorld::CellRefList armors; + MWWorld::CellRefList books; + MWWorld::CellRefList clothes; + MWWorld::CellRefList ingreds; + MWWorld::CellRefList lights; + MWWorld::CellRefList lockpicks; + MWWorld::CellRefList miscItems; + MWWorld::CellRefList probes; + MWWorld::CellRefList repairs; + MWWorld::CellRefList weapons; int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; @@ -120,18 +120,18 @@ namespace MWWorld ContainerStore *mContainer; mutable Ptr mPtr; - MWWorld::ContainerRefList::List::iterator mPotion; - MWWorld::ContainerRefList::List::iterator mApparatus; - MWWorld::ContainerRefList::List::iterator mArmor; - MWWorld::ContainerRefList::List::iterator mBook; - MWWorld::ContainerRefList::List::iterator mClothing; - MWWorld::ContainerRefList::List::iterator mIngredient; - MWWorld::ContainerRefList::List::iterator mLight; - MWWorld::ContainerRefList::List::iterator mLockpick; - MWWorld::ContainerRefList::List::iterator mMiscellaneous; - MWWorld::ContainerRefList::List::iterator mProbe; - MWWorld::ContainerRefList::List::iterator mRepair; - MWWorld::ContainerRefList::List::iterator mWeapon; + MWWorld::CellRefList::List::iterator mPotion; + MWWorld::CellRefList::List::iterator mApparatus; + MWWorld::CellRefList::List::iterator mArmor; + MWWorld::CellRefList::List::iterator mBook; + MWWorld::CellRefList::List::iterator mClothing; + MWWorld::CellRefList::List::iterator mIngredient; + MWWorld::CellRefList::List::iterator mLight; + MWWorld::CellRefList::List::iterator mLockpick; + MWWorld::CellRefList::List::iterator mMiscellaneous; + MWWorld::CellRefList::List::iterator mProbe; + MWWorld::CellRefList::List::iterator mRepair; + MWWorld::CellRefList::List::iterator mWeapon; private: @@ -142,18 +142,18 @@ namespace MWWorld ///< Begin-iterator // construct iterator using a CellRefList iterator - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); void incType(); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 91622c3545..5ec5ca9b56 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -17,9 +17,9 @@ namespace cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) { - if (!iter->second.mBase->mScript.empty() && iter->second.mData.getCount()) + if (!iter->mBase->mScript.empty() && iter->mData.getCount()) { - localScripts.add (iter->second.mBase->mScript, MWWorld::Ptr (&iter->second, cell)); + localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } } } @@ -34,7 +34,7 @@ namespace iter!=cellRefList.mList.end(); ++iter) { - MWWorld::Ptr containerPtr (&iter->second, cell); + MWWorld::Ptr containerPtr (&*iter, cell); MWWorld::ContainerStore& container = MWWorld::Class::get(containerPtr).getContainerStore(containerPtr); for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 768ca9e11c..b917a89168 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -23,7 +23,7 @@ namespace if (!cellRefList.mList.empty()) { const MWWorld::Class& class_ = - MWWorld::Class::get (MWWorld::Ptr (&cellRefList.mList.begin()->second, &cell)); + MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); int numRefs = cellRefList.mList.size(); int current = 0; @@ -33,9 +33,9 @@ namespace MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; - if (it->second.mData.getCount() || it->second.mData.isEnabled()) + if (it->mData.getCount() || it->mData.isEnabled()) { - MWWorld::Ptr ptr (&it->second, &cell); + MWWorld::Ptr ptr (&*it, &cell); try { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp new file mode 100644 index 0000000000..005601cd13 --- /dev/null +++ b/apps/openmw/mwworld/store.cpp @@ -0,0 +1,65 @@ +#include "store.hpp" + +namespace MWWorld { + + +void Store::load(ESM::ESMReader &esm, const std::string &id) +{ + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded! So first, proceed as usual. + + // All cells have a name record, even nameless exterior cells. + std::string idLower = Misc::StringUtils::lowerCase(id); + ESM::Cell *cell = new ESM::Cell; + cell->mName = id; + + // The cell itself takes care of some of the hairy details + cell->load(esm, *mEsmStore); + + if(cell->mData.mFlags & ESM::Cell::Interior) + { + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(idLower)); + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // have new cell replace old cell + *oldcell = *cell; + } else + mInt[idLower] = *cell; + } + else + { + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // merge lists of leased references, use newer data in case of conflict + for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) { + // remove reference from current leased ref tracker and add it to new cell + ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefnum); + if (itold != oldcell->mMovedRefs.end()) { + ESM::MovedCellRef target0 = *itold; + ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); + ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefnum); + wipecell->mLeasedRefs.erase(it_lease); + *itold = *it; + } + } + cell->mMovedRefs = oldcell->mMovedRefs; + // have new cell replace old cell + *oldcell = *cell; + } else + mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; + } + delete cell; +} + +} \ No newline at end of file diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index dbad7432f0..cb18873cc4 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,7 +187,7 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); - typename std::map::const_iterator it = mStatic.find(item.mId); + typename std::map::iterator it = mStatic.find(item.mId); if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { mStatic.erase(it); @@ -523,62 +523,12 @@ namespace MWWorld } } - void load(ESM::ESMReader &esm, const std::string &id) { - // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, - // and we merge all this data into one Cell object. However, we can't simply search for the cell id, - // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they - // are not available until both cells have been loaded! So first, proceed as usual. - - // All cells have a name record, even nameless exterior cells. - std::string idLower = Misc::StringUtils::lowerCase(id); - ESM::Cell *cell = new ESM::Cell; - cell->mName = id; - - // The cell itself takes care of all the hairy details - cell->load(esm, *mEsmStore); - - if(cell->mData.mFlags & ESM::Cell::Interior) - { - // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(idLower)); - if (oldcell) { - // push the new references on the list of references to manage - oldcell->mContextList.push_back(cell->mContextList.at(0)); - // copy list into new cell - cell->mContextList = oldcell->mContextList; - // have new cell replace old cell - *oldcell = *cell; - } else - mInt[idLower] = *cell; - } - else - { - // Store exterior cells by grid position, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); - if (oldcell) { - // push the new references on the list of references to manage - oldcell->mContextList.push_back(cell->mContextList.at(0)); - // copy list into new cell - cell->mContextList = oldcell->mContextList; - // merge lists of leased references, use newer data in case of conflict - for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) { - // remove reference from current leased ref tracker and add it to new cell - if (oldcell->mMovedRefs.find(it->second.mRefnum) != oldcell->mMovedRefs.end()) { - ESM::MovedCellRef target0 = oldcell->mMovedRefs[it->second.mRefnum]; - ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - wipecell->mLeasedRefs.erase(it->second.mRefnum); - } - oldcell->mMovedRefs[it->second.mRefnum] = it->second; - } - cell->mMovedRefs = oldcell->mMovedRefs; - // have new cell replace old cell - *oldcell = *cell; - } else - mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; - } - delete cell; - } - + // HACK: Method implementation had to be moved to a separate cpp file, as we would otherwise get + // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. + // There some nasty three-way cyclic header dependency involved, which I could only fix by moving + // this method. + void load(ESM::ESMReader &esm, const std::string &id); + iterator intBegin() const { return iterator(mSharedInt.begin()); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 62b4f30375..db4fb67ff9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -33,13 +33,13 @@ namespace cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) { - if (!iter->second.mBase->mScript.empty() && iter->second.mData.getCount()) + if (!iter->mBase->mScript.empty() && iter->mData.getCount()) { - if (const ESM::Script *script = store.get().find (iter->second.mBase->mScript)) + if (const ESM::Script *script = store.get().find (iter->mBase->mScript)) { iter->mData.setLocals (*script); - localScripts.add (iter->second.mBase->mScript, MWWorld::Ptr (&iter->second, cell)); + localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } } } @@ -53,10 +53,10 @@ namespace for (iterator iter (refList.mList.begin()); iter!=refList.mList.end(); ++iter) { - if (iter->second.mData.getCount() > 0 && iter->second.mData.getBaseNode()){ - if (iter->second.mData.getHandle()==handle) + if (iter->mData.getCount() > 0 && iter->mData.getBaseNode()){ + if (iter->mData.getHandle()==handle) { - return &iter->second; + return &*iter; } } } @@ -1261,7 +1261,7 @@ namespace MWWorld CellRefList::List& refList = doors.mList; for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = it->second; + MWWorld::LiveCellRef& ref = *it; if (ref.mRef.mTeleport) { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 76a1e4f951..7400fd026c 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -14,6 +14,17 @@ namespace ESM { +/// Some overloaded copare operators. +bool operator==(const MovedCellRef& ref, int pRefnum) +{ + return (ref.mRefnum == pRefnum); +} + +bool operator==(const CellRef& ref, int pRefnum) +{ + return (ref.mRefnum == pRefnum); +} + void CellRef::save(ESMWriter &esm) { esm.writeHNT("FRMR", mRefnum); @@ -134,13 +145,14 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) (int(*)(int)) std::tolower); // Add data required to make reference appear in the correct cell. - /* - std::cout << "Moving refnumber! First cell: " << mData.mX << " " << mData.mY << std::endl; - std::cout << " New cell: " << cMRef.mTarget[0] << " " << cMRef.mTarget[0] << std::endl; - std::cout << "Refnumber (MVRF): " << cMRef.mRefnum << " (FRMR) " << ref.mRefnum << std::endl; - */ - mMovedRefs[cMRef.mRefnum] = cMRef; - cellAlt->mLeasedRefs[ref.mRefnum] = ref; + // We should not need to test for duplicates, as this part of the code is pre-cell merge. + mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(ref); + else + *iter = ref; } // Save position of the cell references and move on diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 6862dbc5c3..27bdd77ce1 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -6,7 +6,7 @@ #include "esmcommon.hpp" #include "defs.hpp" -#include +#include "apps/openmw/mwbase/world.hpp" /* namespace MWWorld { @@ -95,24 +95,29 @@ public: }; /* Moved cell reference tracking object. This mainly stores the target cell - of the reference, so we can easily know where it has been moved when another - plugin tries to move it independently. - */ + of the reference, so we can easily know where it has been moved when another + plugin tries to move it independently. + Unfortunately, we need to implement this here. + */ class MovedCellRef { public: - int mRefnum; - - // Target cell (if exterior) - int mTarget[2]; - - // TODO: Support moving references between exterior and interior cells! - // This may happen in saves, when an NPC follows the player. Tribunal - // introduces a henchman (which no one uses), so we may need this as well. + int mRefnum; + + // Target cell (if exterior) + int mTarget[2]; + + // TODO: Support moving references between exterior and interior cells! + // This may happen in saves, when an NPC follows the player. Tribunal + // introduces a henchman (which no one uses), so we may need this as well. }; -typedef std::map MovedCellRefTracker; -typedef std::map CellRefTracker; +/// Overloaded copare operator used to search inside a list of cell refs. +bool operator==(const MovedCellRef& ref, int pRefnum); +bool operator==(const CellRef& ref, int pRefnum); + +typedef std::list MovedCellRefTracker; +typedef std::list CellRefTracker; /* Cells hold data about objects, creatures, statics (rocks, walls, buildings) and landscape (for exterior cells). Cells frequently From d40ee068975ec80a5acecc7ca686772a554106dd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 9 Feb 2013 15:25:50 +0100 Subject: [PATCH 0296/1483] fixed base/modified logic --- apps/opencs/model/world/columns.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fb94cbf591..cfbd804a5a 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -17,9 +17,9 @@ namespace CSMWorld virtual void set (Record& record, const QVariant& data) { - ESXRecordT base = record.getBase(); - base.mValue = data.toFloat(); - record.setModified (base); + ESXRecordT record2 = record.get(); + record2.mValue = data.toFloat(); + record.setModified (record2); } virtual bool isEditable() const @@ -104,9 +104,9 @@ namespace CSMWorld virtual void set (Record& record, const QVariant& data) { - ESXRecordT base = record.getBase(); - base.mType = static_cast (data.toInt()); - record.setModified (base); + ESXRecordT record2 = record.get(); + record2.mType = static_cast (data.toInt()); + record.setModified (record2); } virtual bool isEditable() const @@ -134,18 +134,18 @@ namespace CSMWorld virtual void set (Record& record, const QVariant& data) { - ESXRecordT base = record.getBase(); + ESXRecordT record2 = record.get(); - switch (record.get().mType) + switch (record2.mType) { - case ESM::VT_String: base.mStr = data.toString().toUtf8().constData(); break; - case ESM::VT_Int: base.mI = data.toInt(); break; - case ESM::VT_Float: base.mF = data.toFloat(); break; + case ESM::VT_String: record2.mStr = data.toString().toUtf8().constData(); break; + case ESM::VT_Int: record2.mI = data.toInt(); break; + case ESM::VT_Float: record2.mF = data.toFloat(); break; default: break; } - record.setModified (base); + record.setModified (record2); } virtual bool isEditable() const From f197c67e95ac189b141ee65bf336b80648f9f3e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 12:46:20 -0800 Subject: [PATCH 0297/1483] Fix a circular include --- components/esm/loadcell.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 27bdd77ce1..a811cab1c5 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -3,17 +3,17 @@ #include #include +#include #include "esmcommon.hpp" #include "defs.hpp" -#include "apps/openmw/mwbase/world.hpp" -/* -namespace MWWorld { - class ESMStore; - class CellStore; + +namespace MWWorld +{ + class ESMStore; } -*/ + namespace ESM { From 8d6f017f171950ddcf64cfdf835677a519407f59 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 13:25:39 -0800 Subject: [PATCH 0298/1483] Remove an unneeded Animation field --- apps/openmw/mwrender/animation.cpp | 6 +----- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 019217ca69..e157afc838 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -22,7 +22,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) - , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mCurrentAnim(NULL) @@ -135,9 +134,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model { mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getName()); - - mStartPosition = mNonAccumRoot->getInitialPosition(); - mLastPosition = mStartPosition; } } } @@ -243,7 +239,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(mStartPosition*mNonAccumRoot->_getDerivedScale() - mLastPosition); + mAccumRoot->setPosition(-mLastPosition * mAccumulate); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 62e93f1100..ee73193bf5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -25,7 +25,6 @@ protected: Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; - Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; std::vector mSkeletonSources; From f4e587c72c9019b388890d2da0a386bcd54228a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 17:48:23 -0800 Subject: [PATCH 0299/1483] Always create a skeleton from a NIF when there's more than one NiNode --- components/nifogre/ogre_nif_loader.cpp | 72 ++++++++++++++++---------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c7f6ac50da..5f7e686a09 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -21,8 +21,6 @@ */ -//loadResource->handleNode->handleNiTriShape->createSubMesh - #include "ogre_nif_loader.hpp" #include @@ -456,30 +454,28 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { + /* If the root node is a NiTriShape, or is a parent to only NiTriShapes, do + * not create a skeleton. */ if(node->recType == Nif::RC_NiTriShape) return false; - if(node->boneTrafo != NULL) + if(node->recType == Nif::RC_NiNode) { - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - skelMgr.create(name, group, true, &sLoaders[name]); - return true; + bool alltrishapes = true; + const Nif::NiNode *ninode = static_cast(node); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length() && alltrishapes;i++) + { + if(!children[i].empty() && children[i]->recType != Nif::RC_NiTriShape) + alltrishapes = false; + } + if(alltrishapes) + return false; } - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - 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())) - return true; - } - } - } - return false; + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + skelMgr.create(name, group, true, &sLoaders[name]); + return true; } }; @@ -1052,7 +1048,7 @@ public: e = e->extra; } - if(node->recType == Nif::RC_NiTriShape) + if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = dynamic_cast(node); mShapeName = shape->name; @@ -1068,11 +1064,8 @@ public: { NIFMeshLoader *loader = &sLoaders[fullname]; *loader = *this; - if(!(flags&0x01)) // Not hidden - { - loader->mShapeIndex = shape->recIndex; - loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); - } + loader->mShapeIndex = shape->recIndex; + loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); @@ -1093,6 +1086,29 @@ public: } } } + + void createEmptyMesh(const Nif::Node *node, MeshInfoList &meshes) + { + /* This creates an empty mesh to which a skeleton gets attached. This + * is to ensure we have an entity with a skeleton instance, even if all + * other meshes are hidden or entities attached to a specific node + * instead of skinned. */ + std::string fullname = mName; + Misc::StringUtils::toLower(fullname); + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + Ogre::MeshPtr mesh = meshMgr.getByName(fullname); + if(mesh.isNull()) + { + NIFMeshLoader *loader = &sLoaders[fullname]; + *loader = *this; + + mesh = meshMgr.createManual(fullname, mGroup, loader); + mesh->setAutoBuildEdgeLists(false); + } + meshes.push_back(MeshInfo(mesh->getName(), (node->parent ? node->parent->name : node->name), + node->trafo.pos, node->trafo.rotation, node->trafo.scale)); + } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; @@ -1135,7 +1151,9 @@ MeshInfoList Loader::load(const std::string &name, const std::string &group) } NIFMeshLoader meshldr(name, group); - meshldr.createMeshes(node, meshes); + if(hasSkel) + meshldr.createEmptyMesh(node, meshes); + meshldr.createMeshes(node, meshes, 0); return meshes; } From 4ee5857bae1285a9334430e140b617ec37d4e05d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 19:09:56 -0800 Subject: [PATCH 0300/1483] Filter accumulation axis for mLastPosition as needed --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e157afc838..9d9631ecea 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -238,8 +238,8 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { - mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(-mLastPosition * mAccumulate); + mLastPosition = mNonAccumRoot->getPosition() * mAccumulate; + mAccumRoot->setPosition(-mLastPosition); } } From bba024d6ad5c2398ee57ff873fb092293d77f618 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Sun, 10 Feb 2013 08:37:45 +0400 Subject: [PATCH 0301/1483] Right mouse button click now stops Container GuiMode. --- apps/openmw/mwinput/inputmanagerimp.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8be..63afa3260b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -579,10 +579,14 @@ namespace MWInput // Toggle between game mode and inventory mode if(gameMode) mWindows.pushGuiMode(MWGui::GM_Inventory); - else if(mWindows.getMode() == MWGui::GM_Inventory) - mWindows.popGuiMode(); + else + { + MWGui::GuiMode mode = mWindows.getMode(); + if(mode == MWGui::GM_Inventory || mode == MWGui::GM_Container) + mWindows.popGuiMode(); + } - // .. but don't touch any other mode. + // .. but don't touch any other mode, except container. } void InputManager::toggleConsole() From 725bfe637218b4b87386f7bb7b385378556319d2 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Sun, 10 Feb 2013 08:50:36 +0400 Subject: [PATCH 0302/1483] TradeWindow: balance now changes per time if user holds +/- button pressed --- apps/openmw/mwgui/tradewindow.cpp | 51 +++++++++++++++++++++++--- apps/openmw/mwgui/tradewindow.hpp | 18 ++++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 51eb3d87ef..2cc8ff4443 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -19,12 +19,17 @@ #include "inventorywindow.hpp" +static const float BALANCE_CHANGE_INITIAL_PAUSE = 0.5; // in seconds +static const float BALANCE_CHANGE_INTERVAL = 0.1; // in seconds + namespace MWGui { TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_trade_window.layout", parWindowManager) , ContainerBase(NULL) // no drag&drop , mCurrentBalance(0) + , mBalanceButtonsState(BBS_None) + , mBalanceChangePause(0.0) { MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; @@ -59,8 +64,10 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); - mIncreaseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonClicked); - mDecreaseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonClicked); + mIncreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonPressed); + mIncreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); + mDecreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonPressed); + mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); setCoord(400, 0, 400, 300); @@ -143,6 +150,21 @@ namespace MWGui } } + void TradeWindow::onFrame(float frameDuration) + { + if (!mMainWidget->getVisible() || mBalanceButtonsState == BBS_None) + return; + + mBalanceChangePause -= frameDuration; + if (mBalanceChangePause < 0.0) { + mBalanceChangePause += BALANCE_CHANGE_INTERVAL; + if (mBalanceButtonsState == BBS_Increase) + onIncreaseButtonTriggered(); + else if (mBalanceButtonsState == BBS_Decrease) + onDecreaseButtonTriggered(); + } + } + void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { const MWWorld::Store &gmst = @@ -242,7 +264,7 @@ namespace MWGui //skill use! MWWorld::Class::get(playerPtr).skillUsageSucceeded(playerPtr, ESM::Skill::Mercantile, 0); - } + } int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); @@ -271,14 +293,33 @@ namespace MWGui mWindowManager.removeGuiMode(GM_Barter); } - void TradeWindow::onIncreaseButtonClicked(MyGUI::Widget* _sender) + void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_Increase; + mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + onIncreaseButtonTriggered(); + } + + void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_Decrease; + mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + onDecreaseButtonTriggered(); + } + + void TradeWindow::onBalanceButtonReleased(MyGUI::Widget *_sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_None; + } + + void TradeWindow::onIncreaseButtonTriggered() { if(mCurrentBalance<=-1) mCurrentBalance -= 1; if(mCurrentBalance>=1) mCurrentBalance += 1; updateLabels(); } - void TradeWindow::onDecreaseButtonClicked(MyGUI::Widget* _sender) + void TradeWindow::onDecreaseButtonTriggered() { if(mCurrentBalance<-1) mCurrentBalance += 1; if(mCurrentBalance>1) mCurrentBalance -= 1; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 219e440369..20d9b60691 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -34,6 +34,8 @@ namespace MWGui void addOrRemoveGold(int gold); + void onFrame(float frameDuration); + protected: MyGUI::Button* mFilterAll; MyGUI::Button* mFilterWeapon; @@ -57,12 +59,24 @@ namespace MWGui int mCurrentBalance; int mCurrentMerchantOffer; + enum BalanceButtonsState { + BBS_None, + BBS_Increase, + BBS_Decrease + } mBalanceButtonsState; + /// pause before next balance change will trigger while user holds +/- button pressed + float mBalanceChangePause; + void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender); - void onIncreaseButtonClicked(MyGUI::Widget* _sender); - void onDecreaseButtonClicked(MyGUI::Widget* _sender); + void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + + void onIncreaseButtonTriggered(); + void onDecreaseButtonTriggered(); // don't show items that the NPC has equipped in his trade-window. virtual bool ignoreEquippedItems() { return true; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8ec495550e..9663def5dd 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -608,6 +608,7 @@ void WindowManager::onFrame (float frameDuration) mHud->onFrame(frameDuration); mTrainingWindow->onFrame (frameDuration); + mTradeWindow->onFrame(frameDuration); mTrainingWindow->checkReferenceAvailable(); mDialogueWindow->checkReferenceAvailable(); From 59808c3e10e0088def9bb4c07f7a5efeb69ab1c6 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Sun, 10 Feb 2013 08:59:38 +0400 Subject: [PATCH 0303/1483] GUI: Birth and Class dialogs now both select 1st item in list at first time. --- apps/openmw/mwgui/birth.cpp | 16 +++++++++++----- apps/openmw/mwgui/class.cpp | 9 ++++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 4837821e0a..99d6605d33 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -133,8 +133,6 @@ void BirthDialog::updateBirths() const MWWorld::Store &signs = MWBase::Environment::get().getWorld()->getStore().get(); - int index = 0; - // sort by name std::vector < std::pair > birthSigns; @@ -145,12 +143,20 @@ void BirthDialog::updateBirths() } std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); - for (std::vector < std::pair >::const_iterator it2 = birthSigns.begin(); it2 != birthSigns.end(); ++it2) + int index = 0; + for (std::vector >::const_iterator it2 = birthSigns.begin(); + it2 != birthSigns.end(); ++it2, ++index) { mBirthList->addItem(it2->second->mName, it2->first); - if (boost::iequals(it2->first, mCurrentBirthId)) + if (mCurrentBirthId.empty()) + { mBirthList->setIndexSelected(index); - ++index; + mCurrentBirthId = it2->first; + } + else if (boost::iequals(it2->first, mCurrentBirthId)) + { + mBirthList->setIndexSelected(index); + } } } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index c14c7f74b5..475efaab31 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -197,8 +197,15 @@ void PickClassDialog::updateClasses() const std::string &id = it->mId; mClassList->addItem(it->mName, id); - if (boost::iequals(id, mCurrentClassId)) + if (mCurrentClassId.empty()) + { + mCurrentClassId = id; mClassList->setIndexSelected(index); + } + else if (boost::iequals(id, mCurrentClassId)) + { + mClassList->setIndexSelected(index); + } ++index; } } From e4ed397b2d35d77398a2d6596657b2a6eba67d74 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sun, 10 Feb 2013 14:02:06 +0100 Subject: [PATCH 0304/1483] Merge plugins and masters list view in openDialog. Simplify datafilesmodel. --- components/fileorderlist/datafileslist.cpp | 68 +---------- components/fileorderlist/datafileslist.hpp | 2 - .../fileorderlist/model/datafilesmodel.cpp | 108 +++--------------- .../fileorderlist/model/datafilesmodel.hpp | 17 +-- 4 files changed, 28 insertions(+), 167 deletions(-) diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index d25060baaf..80d58b35f0 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -48,8 +48,7 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) : QWidget(parent) , mCfgMgr(cfg) { - // Models - mMastersModel = new DataFilesModel(this); + // Model mPluginsModel = new DataFilesModel(this); mPluginsProxyModel = new QSortFilterProxyModel(); @@ -78,29 +77,6 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) QCheckBox checkBox; unsigned int height = checkBox.sizeHint().height() + 4; - mMastersTable = new QTableView(this); - mMastersTable->setModel(mMastersModel); - mMastersTable->setObjectName("MastersTable"); - mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection); - mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mMastersTable->setAlternatingRowColors(true); - mMastersTable->horizontalHeader()->setStretchLastSection(true); - mMastersTable->horizontalHeader()->hide(); - - // Set the row height to the size of the checkboxes - mMastersTable->verticalHeader()->setDefaultSectionSize(height); - mMastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mMastersTable->verticalHeader()->hide(); - mMastersTable->setColumnHidden(1, true); - mMastersTable->setColumnHidden(2, true); - mMastersTable->setColumnHidden(3, true); - mMastersTable->setColumnHidden(4, true); - mMastersTable->setColumnHidden(5, true); - mMastersTable->setColumnHidden(6, true); - mMastersTable->setColumnHidden(7, true); - mMastersTable->setColumnHidden(8, true); - mPluginsTable = new QTableView(this); mPluginsTable->setModel(mPluginsProxyModel); mPluginsTable->setObjectName("PluginsTable"); @@ -124,26 +100,14 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) mPluginsTable->setColumnHidden(7, true); mPluginsTable->setColumnHidden(8, true); - // Add both tables to a splitter - QSplitter *splitter = new QSplitter(this); - splitter->setOrientation(Qt::Horizontal); - splitter->addWidget(mMastersTable); - splitter->addWidget(mPluginsTable); - - // Adjust the default widget widths inside the splitter - QList sizeList; - sizeList << 175 << 200; - splitter->setSizes(sizeList); - QVBoxLayout *pageLayout = new QVBoxLayout(this); pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(splitter); + pageLayout->addWidget(mPluginsTable); connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - - connect(mMastersModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); + + connect(mPluginsModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); @@ -178,7 +142,6 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString { // Set the charset for reading the esm/esp files if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { - mMastersModel->setEncoding(encoding); mPluginsModel->setEncoding(encoding); } @@ -186,11 +149,9 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { QString path = QString::fromStdString(it->string()); path.remove(QChar('\"')); - mMastersModel->addMasters(path); - mPluginsModel->addPlugins(path); + mPluginsModel->addFiles(path); } - mMastersModel->sort(0); mPluginsModel->sort(0); // mMastersTable->sortByColumn(3, Qt::AscendingOrder); // mPluginsTable->sortByColumn(3, Qt::AscendingOrder); @@ -200,11 +161,6 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString void DataFilesList::selectedFiles(std::vector& paths) { - QStringList masterPaths = mMastersModel->checkedItemsPaths(); - foreach (const QString &path, masterPaths) - { - paths.push_back(path.toStdString()); - } QStringList pluginPaths = mPluginsModel->checkedItemsPaths(); foreach (const QString &path, pluginPaths) { @@ -281,19 +237,12 @@ void DataFilesList::setCheckState(QModelIndex index) : mPluginsModel->setCheckState(sourceIndex, Qt::Checked); } - if (object->objectName() == QLatin1String("MastersTable")) { - (mMastersModel->checkState(index) == Qt::Checked) - ? mMastersModel->setCheckState(index, Qt::Unchecked) - : mMastersModel->setCheckState(index, Qt::Checked); - } - return; } void DataFilesList::uncheckAll() { - mMastersModel->uncheckAll(); mPluginsModel->uncheckAll(); } @@ -338,14 +287,9 @@ void DataFilesList::setCheckState(const QString& element, Qt::CheckState state) { mPluginsModel->setCheckState(mPluginsModel->indexFromItem(file), Qt::Checked); } - else - { - file = mMastersModel->findItem(element); - mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); - } } QStringList DataFilesList::checkedFiles() { - return mMastersModel->checkedItems() + mPluginsModel->checkedItems(); + return mPluginsModel->checkedItems(); } \ No newline at end of file diff --git a/components/fileorderlist/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp index 4b158d316d..64584d1fbc 100644 --- a/components/fileorderlist/datafileslist.hpp +++ b/components/fileorderlist/datafileslist.hpp @@ -49,12 +49,10 @@ public slots: void refresh(); private: - DataFilesModel *mMastersModel; DataFilesModel *mPluginsModel; QSortFilterProxyModel *mPluginsProxyModel; - QTableView *mMastersTable; QTableView *mPluginsTable; QMenu *mContextMenu; diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 5bb1996791..4c33a555fa 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -159,7 +159,7 @@ Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const if (!file) return Qt::NoItemFlags; - if (mAvailableFiles.contains(file->fileName())) { + if (canBeChecked(file)) { if (index.column() == 0) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } else { @@ -212,7 +212,6 @@ bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, in QString name = item(index.row())->fileName(); mCheckStates[name] = static_cast(value.toInt()); - emit checkedItemsChanged(checkedItems(), uncheckedItems()); emit layoutChanged(); return true; } @@ -263,73 +262,12 @@ void DataFilesModel::addFile(EsmFile *file) emit endInsertRows(); } -void DataFilesModel::addMasters(const QString &path) +void DataFilesModel::addFiles(const QString &path) { QDir dir(path); - dir.setNameFilters(QStringList(QLatin1String("*.esp"))); - - // Read the dependencies from the plugins - foreach (const QString &path, dir.entryList()) { - try { - ESM::ESMReader fileReader; - ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString())); - fileReader.setEncoder(&encoder); - fileReader.open(dir.absoluteFilePath(path).toStdString()); - - ESM::ESMReader::MasterList mlist = fileReader.getMasters(); - - for (unsigned int i = 0; i < mlist.size(); ++i) { - QString master = QString::fromStdString(mlist[i].name); - - // Add the plugin to the internal dependency map - mDependencies[master].append(path); - - // Don't add esps - if (master.endsWith(".esp", Qt::CaseInsensitive)) - continue; - - QFileInfo info(dir.absoluteFilePath(master)); - - EsmFile *file = new EsmFile(master); - file->setDates(info.lastModified(), info.lastRead()); - file->setPath(info.absoluteFilePath()); - - // Add the master to the table - if (findItem(master) == 0) - addFile(file); - - - } - - } catch(std::runtime_error &e) { - // An error occurred while reading the .esp - qWarning() << "Error reading esp: " << e.what(); - continue; - } - } - - // See if the masters actually exist in the filesystem - dir.setNameFilters(QStringList(QLatin1String("*.esm"))); - - foreach (const QString &path, dir.entryList()) { - QFileInfo info(dir.absoluteFilePath(path)); - - if (findItem(path) == 0) { - EsmFile *file = new EsmFile(path); - file->setDates(info.lastModified(), info.lastRead()); - - addFile(file); - } - - // Make the master selectable - mAvailableFiles.append(path); - } -} - -void DataFilesModel::addPlugins(const QString &path) -{ - QDir dir(path); - dir.setNameFilters(QStringList(QLatin1String("*.esp"))); + QStringList filters; + filters << "*.esp" << "*.esm"; + dir.setNameFilters(filters); foreach (const QString &path, dir.entryList()) { QFileInfo info(dir.absoluteFilePath(path)); @@ -347,9 +285,6 @@ void DataFilesModel::addPlugins(const QString &path) for (unsigned int i = 0; i < mlist.size(); ++i) { QString master = QString::fromStdString(mlist[i].name); masters.append(master); - - // Add the plugin to the internal dependency map - mDependencies[master].append(path); } file->setAuthor(QString::fromStdString(fileReader.getAuthor())); @@ -421,7 +356,7 @@ QStringList DataFilesModel::checkedItems() QString name = file->fileName(); // Only add the items that are in the checked list and available - if (mCheckStates[name] == Qt::Checked && mAvailableFiles.contains(name)) + if (mCheckStates[name] == Qt::Checked && canBeChecked(file)) list << name; } @@ -439,8 +374,8 @@ QStringList DataFilesModel::checkedItemsPaths() for (it = mFiles.constBegin(); it != itEnd; ++it) { EsmFile *file = item(i); ++i; - - if (mCheckStates[file->fileName()] == Qt::Checked && mAvailableFiles.contains(file->fileName())) + + if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file)) list << file->path(); } @@ -475,24 +410,17 @@ QStringList DataFilesModel::uncheckedItems() return list; } -void DataFilesModel::slotcheckedItemsChanged(const QStringList &checkedItems, const QStringList &unCheckedItems) +bool DataFilesModel::canBeChecked(EsmFile *file) const { - emit layoutAboutToBeChanged(); - - QStringList list; - - foreach (const QString &file, checkedItems) { - list << mDependencies[file]; - } - - foreach (const QString &file, unCheckedItems) { - foreach (const QString &remove, mDependencies[file]) { - list.removeAll(remove); + //element can be checked if all its dependencies are + bool canBeChecked = true; + foreach (const QString &master, file->masters()) + { + if (!mCheckStates.contains(master) || mCheckStates[master] != Qt::Checked) + { + canBeChecked = false; + break; } } - - mAvailableFiles.clear(); - mAvailableFiles.append(list); - - emit layoutChanged(); + return canBeChecked; } diff --git a/components/fileorderlist/model/datafilesmodel.hpp b/components/fileorderlist/model/datafilesmodel.hpp index adc80eac2a..0e5008abe1 100644 --- a/components/fileorderlist/model/datafilesmodel.hpp +++ b/components/fileorderlist/model/datafilesmodel.hpp @@ -34,10 +34,7 @@ public: void setEncoding(const QString &encoding); - void addFile(EsmFile *file); - - void addMasters(const QString &path); - void addPlugins(const QString &path); + void addFiles(const QString &path); void uncheckAll(); @@ -51,18 +48,12 @@ public: QModelIndex indexFromItem(EsmFile *item) const; EsmFile* findItem(const QString &name); EsmFile* item(int row) const; - -signals: - void checkedItemsChanged(const QStringList checkedItems, const QStringList unCheckedItems); - -public slots: - void slotcheckedItemsChanged(const QStringList &checkedItems, const QStringList &unCheckedItems); private: + bool canBeChecked(EsmFile *file) const; + void addFile(EsmFile *file); + QList mFiles; - QStringList mAvailableFiles; - - QHash mDependencies; QHash mCheckStates; QString mEncoding; From 0df7c7e5c17aff76fab9c4352a1904271c99c731 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sun, 10 Feb 2013 14:08:54 +0100 Subject: [PATCH 0305/1483] Rename mPlugins* to mFiles* --- components/fileorderlist/datafileslist.cpp | 108 ++++++++++----------- components/fileorderlist/datafileslist.hpp | 6 +- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index 80d58b35f0..5ea2e051df 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -49,11 +49,11 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) , mCfgMgr(cfg) { // Model - mPluginsModel = new DataFilesModel(this); + mFilesModel = new DataFilesModel(this); - mPluginsProxyModel = new QSortFilterProxyModel(); - mPluginsProxyModel->setDynamicSortFilter(true); - mPluginsProxyModel->setSourceModel(mPluginsModel); + mFilesProxyModel = new QSortFilterProxyModel(); + mFilesProxyModel->setDynamicSortFilter(true); + mFilesProxyModel->setSourceModel(mFilesModel); // Filter toolbar QLabel *filterLabel = new QLabel(tr("&Filter:"), this); @@ -77,41 +77,41 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) QCheckBox checkBox; unsigned int height = checkBox.sizeHint().height() + 4; - mPluginsTable = new QTableView(this); - mPluginsTable->setModel(mPluginsProxyModel); - mPluginsTable->setObjectName("PluginsTable"); - mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); - mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mPluginsTable->setSelectionMode(QAbstractItemView::SingleSelection); - mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mPluginsTable->setAlternatingRowColors(true); - mPluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); - mPluginsTable->horizontalHeader()->setStretchLastSection(true); - mPluginsTable->horizontalHeader()->hide(); + mFilesTable = new QTableView(this); + mFilesTable->setModel(mFilesProxyModel); + mFilesTable->setObjectName("PluginsTable"); + mFilesTable->setContextMenuPolicy(Qt::CustomContextMenu); + mFilesTable->setSelectionBehavior(QAbstractItemView::SelectRows); + mFilesTable->setSelectionMode(QAbstractItemView::SingleSelection); + mFilesTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + mFilesTable->setAlternatingRowColors(true); + mFilesTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); + mFilesTable->horizontalHeader()->setStretchLastSection(true); + mFilesTable->horizontalHeader()->hide(); - mPluginsTable->verticalHeader()->setDefaultSectionSize(height); - mPluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mPluginsTable->setColumnHidden(1, true); - mPluginsTable->setColumnHidden(2, true); - mPluginsTable->setColumnHidden(3, true); - mPluginsTable->setColumnHidden(4, true); - mPluginsTable->setColumnHidden(5, true); - mPluginsTable->setColumnHidden(6, true); - mPluginsTable->setColumnHidden(7, true); - mPluginsTable->setColumnHidden(8, true); + mFilesTable->verticalHeader()->setDefaultSectionSize(height); + mFilesTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + mFilesTable->setColumnHidden(1, true); + mFilesTable->setColumnHidden(2, true); + mFilesTable->setColumnHidden(3, true); + mFilesTable->setColumnHidden(4, true); + mFilesTable->setColumnHidden(5, true); + mFilesTable->setColumnHidden(6, true); + mFilesTable->setColumnHidden(7, true); + mFilesTable->setColumnHidden(8, true); QVBoxLayout *pageLayout = new QVBoxLayout(this); pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(mPluginsTable); + pageLayout->addWidget(mFilesTable); - connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(mFilesTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mPluginsModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); + connect(mFilesModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mFilesModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(mFilesTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); createActions(); } @@ -142,17 +142,17 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString { // Set the charset for reading the esm/esp files if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { - mPluginsModel->setEncoding(encoding); + mFilesModel->setEncoding(encoding); } // Add the paths to the respective models for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { QString path = QString::fromStdString(it->string()); path.remove(QChar('\"')); - mPluginsModel->addFiles(path); + mFilesModel->addFiles(path); } - mPluginsModel->sort(0); + mFilesModel->sort(0); // mMastersTable->sortByColumn(3, Qt::AscendingOrder); // mPluginsTable->sortByColumn(3, Qt::AscendingOrder); @@ -161,7 +161,7 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString void DataFilesList::selectedFiles(std::vector& paths) { - QStringList pluginPaths = mPluginsModel->checkedItemsPaths(); + QStringList pluginPaths = mFilesModel->checkedItemsPaths(); foreach (const QString &path, pluginPaths) { paths.push_back(path.toStdString()); @@ -171,11 +171,11 @@ void DataFilesList::selectedFiles(std::vector& paths) void DataFilesList::check() { // Check the current selection - if (!mPluginsTable->selectionModel()->hasSelection()) { + if (!mFilesTable->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); //sort selection ascending because selectedIndexes returns an unsorted list //qSort(indexes.begin(), indexes.end(), rowSmallerThan); @@ -184,18 +184,18 @@ void DataFilesList::check() if (!index.isValid()) return; - mPluginsModel->setCheckState(index, Qt::Checked); + mFilesModel->setCheckState(index, Qt::Checked); } } void DataFilesList::uncheck() { // uncheck the current selection - if (!mPluginsTable->selectionModel()->hasSelection()) { + if (!mFilesTable->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); //sort selection ascending because selectedIndexes returns an unsorted list //qSort(indexes.begin(), indexes.end(), rowSmallerThan); @@ -204,17 +204,17 @@ void DataFilesList::uncheck() if (!index.isValid()) return; - mPluginsModel->setCheckState(index, Qt::Unchecked); + mFilesModel->setCheckState(index, Qt::Unchecked); } } void DataFilesList::refresh() { - mPluginsModel->sort(0); + mFilesModel->sort(0); // Refresh the plugins table - mPluginsTable->scrollToTop(); + mFilesTable->scrollToTop(); } @@ -230,11 +230,11 @@ void DataFilesList::setCheckState(QModelIndex index) return; if (object->objectName() == QLatin1String("PluginsTable")) { - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(index); + QModelIndex sourceIndex = mFilesProxyModel->mapToSource(index); - (mPluginsModel->checkState(sourceIndex) == Qt::Checked) - ? mPluginsModel->setCheckState(sourceIndex, Qt::Unchecked) - : mPluginsModel->setCheckState(sourceIndex, Qt::Checked); + (mFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mFilesModel->setCheckState(sourceIndex, Qt::Checked); } return; @@ -243,25 +243,25 @@ void DataFilesList::setCheckState(QModelIndex index) void DataFilesList::uncheckAll() { - mPluginsModel->uncheckAll(); + mFilesModel->uncheckAll(); } void DataFilesList::filterChanged(const QString filter) { QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); - mPluginsProxyModel->setFilterRegExp(regExp); + mFilesProxyModel->setFilterRegExp(regExp); } void DataFilesList::showContextMenu(const QPoint &point) { // Make sure there are plugins in the view - if (!mPluginsTable->selectionModel()->hasSelection()) { + if (!mFilesTable->selectionModel()->hasSelection()) { return; } - QPoint globalPos = mPluginsTable->mapToGlobal(point); + QPoint globalPos = mFilesTable->mapToGlobal(point); - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); // Show the check/uncheck actions depending on the state of the selected items mUncheckAction->setEnabled(false); @@ -271,7 +271,7 @@ void DataFilesList::showContextMenu(const QPoint &point) if (!index.isValid()) return; - (mPluginsModel->checkState(index) == Qt::Checked) + (mFilesModel->checkState(index) == Qt::Checked) ? mUncheckAction->setEnabled(true) : mCheckAction->setEnabled(true); } @@ -282,14 +282,14 @@ void DataFilesList::showContextMenu(const QPoint &point) void DataFilesList::setCheckState(const QString& element, Qt::CheckState state) { - EsmFile *file = mPluginsModel->findItem(element); + EsmFile *file = mFilesModel->findItem(element); if (file) { - mPluginsModel->setCheckState(mPluginsModel->indexFromItem(file), Qt::Checked); + mFilesModel->setCheckState(mFilesModel->indexFromItem(file), Qt::Checked); } } QStringList DataFilesList::checkedFiles() { - return mPluginsModel->checkedItems(); + return mFilesModel->checkedItems(); } \ No newline at end of file diff --git a/components/fileorderlist/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp index 64584d1fbc..69a20393c2 100644 --- a/components/fileorderlist/datafileslist.hpp +++ b/components/fileorderlist/datafileslist.hpp @@ -49,11 +49,11 @@ public slots: void refresh(); private: - DataFilesModel *mPluginsModel; + DataFilesModel *mFilesModel; - QSortFilterProxyModel *mPluginsProxyModel; + QSortFilterProxyModel *mFilesProxyModel; - QTableView *mPluginsTable; + QTableView *mFilesTable; QMenu *mContextMenu; From 158c6fc9fad2c8e3447e42bd495891d53ea1fbcb Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 10 Feb 2013 14:58:46 +0000 Subject: [PATCH 0306/1483] pressing enter when a messagebox is prompting for "ok", will activate ok button --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/messagebox.cpp | 24 ++++++++++++++++++++++++ apps/openmw/mwgui/messagebox.hpp | 6 +++++- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 13 ++++++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ 7 files changed, 50 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 30bfced06a..4f7435fadc 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -199,6 +199,7 @@ namespace MWBase ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons) = 0; + virtual void enterPressed () = 0; virtual int readPressedButton() = 0; ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index b660af7dd4..08f9508684 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -1,3 +1,5 @@ +#include + #include "messagebox.hpp" using namespace MWGui; @@ -133,6 +135,10 @@ void MessageBoxManager::setMessageBoxSpeed (int speed) mMessageBoxSpeed = speed; } +void MessageBoxManager::enterPressed () +{ + mInterMessageBoxe->enterPressed(); +} int MessageBoxManager::readPressedButton () { @@ -359,7 +365,25 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan } } +void InteractiveMessageBox::enterPressed() +{ + + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) + buttonActivated(*button); + } + +} + void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) +{ + buttonActivated (pressed); +} + +void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) { mMarkedToDelete = true; int index = 0; diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 5e4c468d56..4be8bc5b79 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -34,7 +34,8 @@ namespace MWGui void removeMessageBox (float time, MessageBox *msgbox); bool removeMessageBox (MessageBox *msgbox); void setMessageBoxSpeed (int speed); - + + void enterPressed(); int readPressedButton (); MWBase::WindowManager *mWindowManager; @@ -70,12 +71,15 @@ namespace MWGui { public: InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons); + void enterPressed (); void mousePressed (MyGUI::Widget* _widget); int readPressedButton (); bool mMarkedToDelete; private: + void buttonActivated (MyGUI::Widget* _widget); + MessageBoxManager& mMessageBoxManager; MyGUI::EditPtr mMessageWidget; MyGUI::WidgetPtr mButtonsWidget; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8ec495550e..ae314dd68a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -560,6 +560,11 @@ void WindowManager::messageBox (const std::string& message, const std::vectorenterPressed(); +} + int WindowManager::readPressedButton () { return mMessageBoxManager->readPressedButton(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8bcb88e224..fff627366e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -189,6 +189,7 @@ namespace MWGui virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons); + virtual void enterPressed (); virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual void onFrame (float frameDuration); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8be..153bbba8d9 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -51,6 +51,7 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) + , mEnterPressed(false) { Ogre::RenderWindow* window = ogre.getWindow (); size_t windowHnd; @@ -239,6 +240,10 @@ namespace MWInput void InputManager::update(float dt, bool loading) { + // Pressing enter when a messagebox is prompting for "ok" will activate the ok button + if(mEnterPressed && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox) + MWBase::Environment::get().getWindowManager()->enterPressed(); + // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); @@ -251,7 +256,7 @@ namespace MWInput // update values of channels (as a result of pressed keys) if (!loading) mInputCtrl->update(dt); - + // Update windows/gui as a result of input events // For instance this could mean opening a new window/dialog, // by doing this after the input events are handled we @@ -426,6 +431,9 @@ namespace MWInput bool InputManager::keyPressed( const OIS::KeyEvent &arg ) { + if(arg.key == OIS::KC_RETURN && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console) + mEnterPressed = true; + mInputCtrl->keyPressed (arg); unsigned int text = arg.text; #ifdef __APPLE__ // filter \016 symbol for F-keys on OS X @@ -442,6 +450,9 @@ namespace MWInput bool InputManager::keyReleased( const OIS::KeyEvent &arg ) { + if(arg.key == OIS::KC_RETURN) + mEnterPressed = false; + mInputCtrl->keyReleased (arg); MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key)); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f285..c7ba7b7565 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -151,6 +151,8 @@ namespace MWInput std::map mControlSwitch; + bool mEnterPressed; + private: void adjustMouseRegion(int width, int height); From c32c31f6d642c38450b03076319d7d73d72b161c Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 10 Feb 2013 15:41:02 +0000 Subject: [PATCH 0307/1483] break after activating button --- apps/openmw/mwgui/messagebox.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 08f9508684..896ab3bb56 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -373,7 +373,10 @@ void InteractiveMessageBox::enterPressed() for(button = mButtons.begin(); button != mButtons.end(); ++button) { if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) + { buttonActivated(*button); + break; + } } } From eb6590f7d88ef0027bb3ab59c44cd2507168c457 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Feb 2013 17:21:25 +0100 Subject: [PATCH 0308/1483] added delegate factory --- apps/opencs/view/doc/viewmanager.cpp | 6 +++- apps/opencs/view/doc/viewmanager.hpp | 6 ++++ apps/opencs/view/world/table.cpp | 7 +++- apps/opencs/view/world/util.cpp | 53 ++++++++++++++++++++++++++++ apps/opencs/view/world/util.hpp | 48 +++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index b01b9ce342..2a6309da1c 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -6,6 +6,8 @@ #include "../../model/doc/documentmanager.hpp" #include "../../model/doc/document.hpp" +#include "../world/util.hpp" + #include "view.hpp" void CSVDoc::ViewManager::updateIndices() @@ -29,11 +31,13 @@ void CSVDoc::ViewManager::updateIndices() CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager) { - + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; } CSVDoc::ViewManager::~ViewManager() { + delete mDelegateFactories; + for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; } diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 91a80d4962..72e7a3e1a1 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -11,6 +11,11 @@ namespace CSMDoc class DocumentManager; } +namespace CSVWorld +{ + class CommandDelegateFactoryCollection; +} + namespace CSVDoc { class View; @@ -21,6 +26,7 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; + CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; // not implemented ViewManager (const ViewManager&); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 0721ead2c0..f9167d2591 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -102,7 +102,12 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q if (flags & CSMWorld::ColumnBase::Flag_Table) { - CommandDelegate *delegate = new CommandDelegate (undoStack, this); + CSMWorld::ColumnBase::Display display = static_cast ( + mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display, + undoStack, this); + mDelegates.push_back (delegate); setItemDelegateForColumn (i, delegate); } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 7181dd4d17..85fda2dad1 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -1,6 +1,8 @@ #include "util.hpp" +#include + #include #include "../../model/world/commands.hpp" @@ -35,6 +37,57 @@ QVariant CSVWorld::NastyTableModelHack::getData() const return mData; } + +CSVWorld::CommandDelegateFactory::~CommandDelegateFactory() {} + + +CSVWorld::CommandDelegateFactoryCollection *CSVWorld::CommandDelegateFactoryCollection::sThis = 0; + +CSVWorld::CommandDelegateFactoryCollection::CommandDelegateFactoryCollection() +{ + if (sThis) + throw std::logic_error ("multiple instances of CSVWorld::CommandDelegateFactoryCollection"); + + sThis = this; +} + +CSVWorld::CommandDelegateFactoryCollection::~CommandDelegateFactoryCollection() +{ + sThis = 0; + + for (std::map::iterator iter ( + mFactories.begin()); + iter!=mFactories.end(); ++iter) + delete iter->second; +} + +void CSVWorld::CommandDelegateFactoryCollection::add (CSMWorld::ColumnBase::Display display, + CommandDelegateFactory *factory) +{ + mFactories.insert (std::make_pair (display, factory)); +} + +CSVWorld::CommandDelegate *CSVWorld::CommandDelegateFactoryCollection::makeDelegate ( + CSMWorld::ColumnBase::Display display, QUndoStack& undoStack, QObject *parent) const +{ + std::map::const_iterator iter = + mFactories.find (display); + + if (iter!=mFactories.end()) + return iter->second->makeDelegate (undoStack, parent); + + return new CommandDelegate (undoStack, parent); +} + +const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFactoryCollection::get() +{ + if (!sThis) + throw std::logic_error ("no instance of CSVWorld::CommandDelegateFactoryCollection"); + + return *sThis; +} + + CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) : QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) {} diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 1365831186..79f30da2c2 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -1,9 +1,13 @@ #ifndef CSV_WORLD_UTIL_H #define CSV_WORLD_UTIL_H +#include + #include #include +#include "../../model/world/columnbase.hpp" + class QUndoStack; namespace CSVWorld @@ -31,6 +35,50 @@ namespace CSVWorld QVariant getData() const; }; + class CommandDelegate; + + class CommandDelegateFactory + { + public: + + virtual ~CommandDelegateFactory(); + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const = 0; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + }; + + class CommandDelegateFactoryCollection + { + static CommandDelegateFactoryCollection *sThis; + std::map mFactories; + + private: + + // not implemented + CommandDelegateFactoryCollection (const CommandDelegateFactoryCollection&); + CommandDelegateFactoryCollection& operator= (const CommandDelegateFactoryCollection&); + + public: + + CommandDelegateFactoryCollection(); + + ~CommandDelegateFactoryCollection(); + + void add (CSMWorld::ColumnBase::Display display, CommandDelegateFactory *factory); + ///< The ownership of \æ factory is transferred to *this. + /// + /// This function must not be called more than once per value of \æ display. + + CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, QUndoStack& undoStack, + QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + /// + /// If no factory is registered for \a display, a CommandDelegate will be returned. + + static const CommandDelegateFactoryCollection& get(); + + }; + ///< \brief Use commands instead of manipulating the model directly class CommandDelegate : public QStyledItemDelegate { From f4d60ae7b203b90c9714fff9fa81eb06a79f278e Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sun, 10 Feb 2013 19:59:25 +0100 Subject: [PATCH 0309/1483] Files sorting (masters then plugins). Remove unneeded includes. --- apps/launcher/datafilespage.cpp | 7 --- components/fileorderlist/datafileslist.cpp | 1 - .../fileorderlist/model/datafilesmodel.cpp | 44 +++++-------------- .../fileorderlist/model/esm/esmfile.hpp | 18 ++++---- 4 files changed, 21 insertions(+), 49 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 52b8c9cbeb..8afece00b3 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -7,12 +7,7 @@ #include #include -////#include "model/datafilesmodel.hpp" -////#include "model/esm/esmfile.hpp" - #include "utils/profilescombobox.hpp" -////#include "utils/filedialog.hpp" -////#include "utils/naturalsort.hpp" #include "utils/textinputdialog.hpp" #include "datafilespage.hpp" @@ -527,7 +522,5 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); mDataFilesList->uncheckAll(); - ////mMastersModel->uncheckAll(); - ////mPluginsModel->uncheckAll(); readConfig(); } diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index 5ea2e051df..2f1b555c19 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -8,7 +8,6 @@ #include "utils/filedialog.hpp" #include "utils/lineedit.hpp" -#include "utils/naturalsort.hpp" #include "datafileslist.hpp" diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 4c33a555fa..682ef01287 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -8,8 +8,6 @@ #include "esm/esmfile.hpp" -#include "../utils/naturalsort.hpp" - #include "datafilesmodel.hpp" DataFilesModel::DataFilesModel(QObject *parent) : @@ -219,39 +217,21 @@ bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, in return false; } +bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2) +{ + //Masters first then alphabetically + if (e1->fileName().endsWith(".esm") && !e2->fileName().endsWith(".esm")) + return true; + if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) + return false; + + return e1->fileName().toLower() < e2->fileName().toLower(); +} + void DataFilesModel::sort(int column, Qt::SortOrder order) { - // TODO: Make this more efficient emit layoutAboutToBeChanged(); - - QList sortedFiles; - - QMultiMap timestamps; - - foreach (EsmFile *file, mFiles) - timestamps.insert(file->modified().toString(Qt::ISODate), file->fileName()); - - QMapIterator ti(timestamps); - - while (ti.hasNext()) { - ti.next(); - - QModelIndex index = indexFromItem(findItem(ti.value())); - - if (!index.isValid()) - continue; - - EsmFile *file = item(index.row()); - - if (!file) - continue; - - sortedFiles.append(file); - } - - mFiles.clear(); - mFiles = sortedFiles; - + qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile); emit layoutChanged(); } diff --git a/components/fileorderlist/model/esm/esmfile.hpp b/components/fileorderlist/model/esm/esmfile.hpp index ad267aa753..52b3fbd007 100644 --- a/components/fileorderlist/model/esm/esmfile.hpp +++ b/components/fileorderlist/model/esm/esmfile.hpp @@ -26,15 +26,15 @@ public: void setMasters(const QStringList &masters); void setDescription(const QString &description); - inline QString fileName() { return mFileName; } - inline QString author() { return mAuthor; } - inline int size() { return mSize; } - inline QDateTime modified() { return mModified; } - inline QDateTime accessed() { return mAccessed; } - inline float version() { return mVersion; } - inline QString path() { return mPath; } - inline QStringList masters() { return mMasters; } - inline QString description() { return mDescription; } + inline QString fileName() const { return mFileName; } + inline QString author() const { return mAuthor; } + inline int size() const { return mSize; } + inline QDateTime modified() const { return mModified; } + inline QDateTime accessed() const { return mAccessed; } + inline float version() const { return mVersion; } + inline QString path() const { return mPath; } + inline QStringList masters() const { return mMasters; } + inline QString description() const { return mDescription; } private: From 62c711d709d9c3bf314b97bd31b198f3768255e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 11 Feb 2013 02:28:02 +0100 Subject: [PATCH 0310/1483] Small change to delete microcode cache more aggressively. --- extern/shiny/Main/Factory.cpp | 18 +++++++++++------- extern/shiny/Main/Factory.hpp | 5 ++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 21f13e30b6..40c695fd4a 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -15,6 +15,7 @@ namespace sh { Factory* Factory::sThis = 0; + const std::string Factory::mBinaryCacheName = "binaryCache"; Factory& Factory::getInstance() { @@ -198,16 +199,16 @@ namespace sh if (mShadersLastModified[sourceRelative] != lastModified) { // delete any outdated shaders based on this shader set - removeCache (it->first); - // remove the whole binary cache (removing only the individual shaders does not seem to be possible at this point with OGRE) - removeBinaryCache = true; + if (removeCache (it->first)) + removeBinaryCache = true; } } else { // if we get here, this is either the first run or a new shader file was added // in both cases we can safely delete - removeCache (it->first); + if (removeCache (it->first)) + removeBinaryCache = true; } mShaderSets.insert(std::make_pair(it->first, newSet)); } @@ -304,7 +305,7 @@ namespace sh if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache) { - std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; + std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; if (boost::filesystem::exists(file)) { mPlatform->deserializeShaders (file); @@ -316,7 +317,7 @@ namespace sh { if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache) { - std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; + std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; mPlatform->serializeShaders (file); } @@ -590,8 +591,9 @@ namespace sh m->createForConfiguration (configuration, 0); } - void Factory::removeCache(const std::string& pattern) + bool Factory::removeCache(const std::string& pattern) { + bool ret = false; if ( boost::filesystem::exists(mPlatform->getCacheFolder()) && boost::filesystem::is_directory(mPlatform->getCacheFolder())) { @@ -620,10 +622,12 @@ namespace sh if (shaderName == pattern) { boost::filesystem::remove(file); + ret = true; std::cout << "Removing outdated shader: " << file << std::endl; } } } } + return ret; } } diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp index 6d4175c976..846860b89a 100644 --- a/extern/shiny/Main/Factory.hpp +++ b/extern/shiny/Main/Factory.hpp @@ -203,7 +203,10 @@ namespace sh MaterialInstance* findInstance (const std::string& name); MaterialInstance* searchInstance (const std::string& name); - void removeCache (const std::string& pattern); + /// @return was anything removed? + bool removeCache (const std::string& pattern); + + static const std::string mBinaryCacheName; }; } From 55dd17c27c81268916b6045e828029cd4ed31c2f Mon Sep 17 00:00:00 2001 From: graffy76 Date: Mon, 11 Feb 2013 04:30:16 -0600 Subject: [PATCH 0311/1483] Added setBarColor() function to CSVDoc::Operation. Created four color types for existing operations (save, verify, compile and search), with a default for future / undefined ops. --- apps/opencs/view/doc/operation.cpp | 70 +++++++++++++++++++++++++++++- apps/opencs/view/doc/operation.hpp | 6 ++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 3f415da032..c301195bc7 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -35,7 +35,7 @@ void CSVDoc::Operation::updateLabel (int threads) CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) { /// \todo Add a cancel button or a pop up menu with a cancel item - + setBarColor( type); updateLabel(); /// \todo assign different progress bar colours to allow the user to distinguish easily between operation types @@ -51,4 +51,70 @@ void CSVDoc::Operation::setProgress (int current, int max, int threads) int CSVDoc::Operation::getType() const { return mType; -} \ No newline at end of file +} + +void CSVDoc::Operation::setBarColor (int type) +{ + QString style ="QProgressBar {" + "text-align: center;" + "}" + "QProgressBar::chunk {" + "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 %1, stop:.50 %2 stop: .51 %3 stop:1 %4);" + "text-align: center;" + "margin: 2px 1px 1p 2px;" + "}"; + + // "QProgressBar::chunk {background-color: %1;}"; + + QString topColor = "#F2F6F8"; + QString bottomColor = "#E0EFF9"; + QString midTopColor = "#D8E1E7"; + QString midBottomColor = "#B5C6D0"; // default gray gloss + + // colors inspired by samples from: + // http://www.colorzilla.com/gradient-editor/ + + switch (type) + { + case CSMDoc::State_Saving: + + topColor = "#FECCB1"; + midTopColor = "#F17432"; + midBottomColor = "#EA5507"; + bottomColor = "#FB955E"; // red gloss #2 + //break; + + case CSMDoc::State_Searching: + + topColor = "#EBF1F6"; + midTopColor = "#ABD3EE"; + midBottomColor = "#89C3EB"; + bottomColor = "#D5EBFB"; //blue gloss #4 + //break; + + case CSMDoc::State_Verifying: + + topColor = "#BFD255"; + midTopColor = "#8EB92A"; + midBottomColor = "#72AA00"; + bottomColor = "#9ECB2D"; //green gloss + //break; + + case CSMDoc::State_Compiling: + + topColor = "#F3E2C7"; + midTopColor = "#C19E67"; + midBottomColor = "#B68D4C"; + bottomColor = "#E9D4B3"; //l Brown 3D + //break; + + default: + + topColor = "#F2F6F8"; + bottomColor = "#E0EFF9"; + midTopColor = "#D8E1E7"; + midBottomColor = "#B5C6D0"; // gray gloss for undefined ops + } + + setStyleSheet(style.arg(topColor).arg(midTopColor).arg(midBottomColor).arg(bottomColor)); +} diff --git a/apps/opencs/view/doc/operation.hpp b/apps/opencs/view/doc/operation.hpp index 362725b6f4..a5abf73b79 100644 --- a/apps/opencs/view/doc/operation.hpp +++ b/apps/opencs/view/doc/operation.hpp @@ -25,7 +25,11 @@ namespace CSVDoc void setProgress (int current, int max, int threads); int getType() const; + + private: + + void setBarColor (int type); }; } -#endif \ No newline at end of file +#endif From aa2547151769a91b6a84704ab338b0bdee4ecac3 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 11 Feb 2013 15:01:00 +0100 Subject: [PATCH 0312/1483] WIP: working on improving the config file handling --- apps/launcher/CMakeLists.txt | 6 + apps/launcher/datafilespage.cpp | 295 +++++++++----------- apps/launcher/datafilespage.hpp | 14 +- apps/launcher/main.cpp | 34 ++- apps/launcher/maindialog.cpp | 79 ++++-- apps/launcher/maindialog.hpp | 16 +- apps/launcher/model/datafilesmodel.cpp | 4 +- apps/launcher/settings/gamesettings.cpp | 9 +- apps/launcher/settings/launchersettings.cpp | 45 +++ apps/launcher/settings/launchersettings.hpp | 16 ++ apps/launcher/settings/settingsbase.hpp | 23 +- apps/launcher/utils/lineedit.cpp | 13 +- apps/launcher/utils/lineedit.hpp | 2 +- apps/launcher/utils/profilescombobox.cpp | 65 ++++- apps/launcher/utils/profilescombobox.hpp | 4 +- 15 files changed, 404 insertions(+), 221 deletions(-) create mode 100644 apps/launcher/settings/launchersettings.cpp create mode 100644 apps/launcher/settings/launchersettings.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 044a0a0b73..3c721e2386 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -11,7 +11,9 @@ set(LAUNCHER settings/gamesettings.cpp settings/graphicssettings.cpp + settings/launchersettings.cpp + utils/comboboxlineedit.cpp utils/naturalsort.cpp utils/lineedit.cpp utils/profilescombobox.cpp @@ -32,8 +34,10 @@ set(LAUNCHER_HEADER settings/gamesettings.hpp settings/graphicssettings.hpp + settings/launchersettings.hpp settings/settingsbase.hpp + utils/comboboxlineedit.cpp utils/lineedit.hpp utils/naturalsort.hpp utils/profilescombobox.hpp @@ -52,6 +56,7 @@ set(LAUNCHER_HEADER_MOC model/modelitem.hpp model/esm/esmfile.hpp + utils/comboboxlineedit.hpp utils/lineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp @@ -86,6 +91,7 @@ ENDIF(OGRE_STATIC) add_executable(omwlauncher ${GUI_TYPE} ${LAUNCHER} + ${LAUNCHER_HEADER} ${RCC_SRCS} ${MOC_SRCS} ) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index e253003940..12323b1f19 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -7,6 +7,7 @@ #include "model/esm/esmfile.hpp" #include "settings/gamesettings.hpp" +#include "settings/launchersettings.hpp" #include "utils/profilescombobox.hpp" #include "utils/lineedit.hpp" @@ -47,9 +48,10 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) return index1.row() <= index2.row(); } -DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, QWidget *parent) +DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent) : mCfgMgr(cfg) , mGameSettings(gameSettings) + , mLauncherSettings(launcherSettings) , QWidget(parent) { // Models @@ -129,15 +131,19 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mPluginsTable->setColumnHidden(8, true); // Add both tables to a splitter - QSplitter *splitter = new QSplitter(this); - splitter->setOrientation(Qt::Horizontal); - splitter->addWidget(mMastersTable); - splitter->addWidget(mPluginsTable); + mSplitter = new QSplitter(this); + mSplitter->setOrientation(Qt::Horizontal); + mSplitter->setChildrenCollapsible(false); // Don't allow the widgets to be hidden + mSplitter->addWidget(mMastersTable); + mSplitter->addWidget(mPluginsTable); // Adjust the default widget widths inside the splitter QList sizeList; - sizeList << 175 << 200; - splitter->setSizes(sizeList); + sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt(); + sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt(); + qDebug() << sizeList; + + mSplitter->setSizes(sizeList); // Bottom part with profile options QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); @@ -158,7 +164,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam QVBoxLayout *pageLayout = new QVBoxLayout(this); pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(splitter); + pageLayout->addWidget(mSplitter); pageLayout->addWidget(mProfileToolBar); // Create a dialog for the new profile name input @@ -178,8 +184,9 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); + connect(mSplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); + createActions(); - setupConfig(); setupDataFiles(); } @@ -221,126 +228,50 @@ void DataFilesPage::createActions() } -void DataFilesPage::setupConfig() -{ - // Open our config file - QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); - mLauncherConfig = new QSettings(config, QSettings::IniFormat); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - QStringList profiles = mLauncherConfig->childGroups(); - - // Add the profiles to the combobox - foreach (const QString &profile, profiles) { - - if (profile.contains(QRegExp("[^a-zA-Z0-9_]"))) - continue; // Profile name contains garbage - - - qDebug() << "adding " << profile; - mProfilesComboBox->addItem(profile); - } - - // Add a default profile - if (mProfilesComboBox->findText(QString("Default")) == -1) { - mProfilesComboBox->addItem(QString("Default")); - } - - QString currentProfile = mLauncherConfig->value("CurrentProfile").toString(); - - if (currentProfile.isEmpty()) { - // No current profile selected - currentProfile = "Default"; - } - - const int currentIndex = mProfilesComboBox->findText(currentProfile); - if (currentIndex != -1) { - // Profile is found - mProfilesComboBox->setCurrentIndex(currentIndex); - } - - mLauncherConfig->endGroup(); -} - - void DataFilesPage::readConfig() { - // Don't read the config if no masters are found - if (mMastersModel->rowCount() < 1) - return; +// // Don't read the config if no masters are found +// if (mMastersModel->rowCount() < 1) +// return; - QString profile = mProfilesComboBox->currentText(); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - mLauncherConfig->beginGroup(profile); - - QStringList childKeys = mLauncherConfig->childKeys(); - QStringList plugins; - - // Sort the child keys numerical instead of alphabetically - // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 - qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); - - foreach (const QString &key, childKeys) { - const QString keyValue = mLauncherConfig->value(key).toString(); - - if (key.startsWith("Plugin")) { - //QStringList checked = mPluginsModel->checkedItems(); - EsmFile *file = mPluginsModel->findItem(keyValue); - QModelIndex index = mPluginsModel->indexFromItem(file); - - mPluginsModel->setCheckState(index, Qt::Checked); - // Move the row to the top of te view - //mPluginsModel->moveRow(index.row(), checked.count()); - plugins << keyValue; - } - - if (key.startsWith("Master")) { - EsmFile *file = mMastersModel->findItem(keyValue); - mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); - } - } - - qDebug() << plugins; - - -// // Set the checked item positions -// const QStringList checked = mPluginsModel->checkedItems(); -// for (int i = 0; i < plugins.size(); ++i) { -// EsmFile *file = mPluginsModel->findItem(plugins.at(i)); -// QModelIndex index = mPluginsModel->indexFromItem(file); -// mPluginsModel->moveRow(index.row(), i); -// qDebug() << "Moving: " << plugins.at(i) << " from: " << index.row() << " to: " << i << " count: " << checked.count(); +// QString profile = mProfilesComboBox->currentText(); +// // Make sure we have no groups open +// while (!mLauncherConfig->group().isEmpty()) { +// mLauncherConfig->endGroup(); // } - // Iterate over the plugins to set their checkstate and position -// for (int i = 0; i < plugins.size(); ++i) { -// const QString plugin = plugins.at(i); +// mLauncherConfig->beginGroup("Profiles"); +// mLauncherConfig->beginGroup(profile); -// const QList pluginList = mPluginsModel->findItems(plugin); +// QStringList childKeys = mLauncherConfig->childKeys(); +// QStringList plugins; -// if (!pluginList.isEmpty()) -// { -// foreach (const QStandardItem *currentPlugin, pluginList) { -// mPluginsModel->setData(currentPlugin->index(), Qt::Checked, Qt::CheckStateRole); +// // Sort the child keys numerical instead of alphabetically +// // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 +// qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); -// // Move the plugin to the position specified in the config file -// mPluginsModel->insertRow(i, mPluginsModel->takeRow(currentPlugin->row())); -// } +// foreach (const QString &key, childKeys) { +// const QString keyValue = mLauncherConfig->value(key).toString(); + +// if (key.startsWith("Plugin")) { +// //QStringList checked = mPluginsModel->checkedItems(); +// EsmFile *file = mPluginsModel->findItem(keyValue); +// QModelIndex index = mPluginsModel->indexFromItem(file); + +// mPluginsModel->setCheckState(index, Qt::Checked); +// // Move the row to the top of te view +// //mPluginsModel->moveRow(index.row(), checked.count()); +// plugins << keyValue; +// } + +// if (key.startsWith("Master")) { +// EsmFile *file = mMastersModel->findItem(keyValue); +// mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); // } // } +// qDebug() << plugins; } void DataFilesPage::setupDataFiles() @@ -362,10 +293,43 @@ void DataFilesPage::setupDataFiles() mPluginsModel->addPlugins(dataLocal); } + loadSettings(); +} + +void DataFilesPage::loadSettings() +{ + qDebug() << "load settings"; +} + +void DataFilesPage::saveSettings() +{ + QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + qDebug() << "save settings" << profile; + + QStringList items = mMastersModel->checkedItems(); + + foreach(const QString &master, items) { + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), master); + } + + items.clear(); + items = mPluginsModel->checkedItems(); + + qDebug() << items.size(); + + foreach(const QString &plugin, items) { + qDebug() << "setting " << plugin; + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), plugin); + } + + + } void DataFilesPage::writeConfig(QString profile) { + + // // Don't overwrite the config if no masters are found // if (mMastersModel->rowCount() < 1) // return; @@ -518,21 +482,22 @@ void DataFilesPage::writeConfig(QString profile) void DataFilesPage::newProfile() { - if (mNewProfileDialog->exec() == QDialog::Accepted) { +// if (mNewProfileDialog->exec() == QDialog::Accepted) { - const QString text = mNewProfileDialog->lineEdit()->text(); - mProfilesComboBox->addItem(text); +// const QString text = mNewProfileDialog->lineEdit()->text(); +// mProfilesComboBox->addItem(text); +// mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); +// } - // Copy the currently checked items to cfg - writeConfig(text); - mLauncherConfig->sync(); - - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); - } + mDeleteProfileAction->setEnabled(false); + mProfilesComboBox->setCurrentIndex(-1); + mProfilesComboBox->setEditEnabled(true); + mProfilesComboBox->lineEdit()->setFocus(); } void DataFilesPage::updateOkButton(const QString &text) { + // We do this here because we need the profiles combobox text if (text.isEmpty()) { mNewProfileDialog->setOkButtonEnabled(false); return; @@ -543,6 +508,16 @@ void DataFilesPage::updateOkButton(const QString &text) : mNewProfileDialog->setOkButtonEnabled(false); } +void DataFilesPage::updateSplitter() +{ + // Sigh, update the saved splitter size in settings only when moved + // Since getting mSplitter->sizes() if page is hidden returns invalid values + QList sizes = mSplitter->sizes(); + + mLauncherSettings.setValue(QString("General/MastersTable/width"), QString::number(sizes.at(0))); + mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1))); +} + void DataFilesPage::deleteProfile() { QString profile = mProfilesComboBox->currentText(); @@ -562,18 +537,8 @@ void DataFilesPage::deleteProfile() msgBox.exec(); if (msgBox.clickedButton() == deleteButton) { - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - - // Open the profile-name subgroup - mLauncherConfig->beginGroup(profile); - mLauncherConfig->remove(""); // Clear the subgroup - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); // Remove the profile from the combobox mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); @@ -624,11 +589,8 @@ void DataFilesPage::refresh() { mPluginsModel->sort(0); - // Refresh the plugins table mPluginsTable->scrollToTop(); - writeConfig(); - readConfig(); } @@ -679,50 +641,43 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre mProfilesComboBox->setEditEnabled(true); } - if (!previous.isEmpty()) { - writeConfig(previous); - mLauncherConfig->sync(); - - if (mProfilesComboBox->currentIndex() == -1) - return; - - } else { + if (previous.isEmpty()) return; - } + + if (mProfilesComboBox->findText(previous) == -1) + return; // Profile was deleted + + // Store the previous profile + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), previous); + saveSettings(); + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); + mMastersModel->uncheckAll(); mPluginsModel->uncheckAll(); - readConfig(); + loadSettings(); } void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) { + qDebug() << "rename"; if (previous.isEmpty()) return; // Save the new profile name - writeConfig(current); + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); + saveSettings(); - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } + // Remove the old one + mLauncherSettings.remove(QString("Profiles/") + previous + QString("/master")); + mLauncherSettings.remove(QString("Profiles/") + previous + QString("/plugin")); - mLauncherConfig->beginGroup("Profiles"); + // Remove the profile from the combobox + mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - // Open the profile-name subgroup - mLauncherConfig->beginGroup(previous); - mLauncherConfig->remove(""); // Clear the subgroup - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - mLauncherConfig->sync(); - - // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); - readConfig(); + mMastersModel->uncheckAll(); + mPluginsModel->uncheckAll(); + loadSettings(); } void DataFilesPage::showContextMenu(const QPoint &point) diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index e40d29d602..2dbbdb6679 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -6,16 +6,18 @@ class QTableView; class QSortFilterProxyModel; -class QSettings; class QAction; class QToolBar; +class QSplitter; class QMenu; + class ProfilesComboBox; class DataFilesModel; class TextInputDialog; class ProfilesComboBox; class GameSettings; +class LauncherSettings; namespace Files { struct ConfigurationManager; } @@ -24,11 +26,13 @@ class DataFilesPage : public QWidget Q_OBJECT public: - DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, QWidget *parent = 0); + DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0); ProfilesComboBox *mProfilesComboBox; void writeConfig(QString profile = QString()); + void saveSettings(); + public slots: void setCheckState(QModelIndex index); @@ -38,6 +42,7 @@ public slots: void profileChanged(const QString &previous, const QString ¤t); void profileRenamed(const QString &previous, const QString ¤t); void updateOkButton(const QString &text); + void updateSplitter(); // Action slots void newProfile(); @@ -61,6 +66,7 @@ private: QToolBar *mProfileToolBar; QMenu *mContextMenu; + QSplitter *mSplitter; QAction *mNewProfileAction; QAction *mDeleteProfileAction; @@ -74,8 +80,8 @@ private: Files::ConfigurationManager &mCfgMgr; - QSettings *mLauncherConfig; GameSettings &mGameSettings; + LauncherSettings &mLauncherSettings; TextInputDialog *mNewProfileDialog; @@ -87,6 +93,8 @@ private: void setupConfig(); void readConfig(); + void loadSettings(); + }; #endif diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 43bf50fbc7..ba84518c1e 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -16,6 +16,7 @@ #include "maindialog.hpp" #include "settings/gamesettings.hpp" #include "settings/graphicssettings.hpp" +#include "settings/launchersettings.hpp" int main(int argc, char *argv[]) @@ -52,6 +53,7 @@ int main(int argc, char *argv[]) GameSettings gameSettings(cfgMgr); GraphicsSettings graphicsSettings; + LauncherSettings launcherSettings; QStringList paths; paths.append(userPath + QString("openmw.cfg")); @@ -118,8 +120,6 @@ int main(int argc, char *argv[]) } // On to the graphics settings - qDebug() << userPath; - QFile localDefault(QString("settings-default.cfg")); QFile globalDefault(globalPath + QString("settings-default.cfg")); @@ -163,8 +163,36 @@ int main(int argc, char *argv[]) file.close(); } + // Now the launcher settings + paths.clear(); + paths.append(QString("launcher.cfg")); + paths.append(userPath + QString("launcher.cfg")); - MainDialog mainWin(gameSettings, graphicsSettings); + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error opening OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return 0; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + launcherSettings.readFile(stream); + } + file.close(); + } + + + MainDialog mainWin(gameSettings, graphicsSettings, launcherSettings); if (mainWin.setup()) { mainWin.show(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 4d3d24bd91..f48ea603bf 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -2,6 +2,7 @@ #include "settings/gamesettings.hpp" #include "settings/graphicssettings.hpp" +#include "settings/launchersettings.hpp" #include "utils/profilescombobox.hpp" @@ -11,9 +12,11 @@ #include "datafilespage.hpp" MainDialog::MainDialog(GameSettings &gameSettings, - GraphicsSettings &graphicsSettings) + GraphicsSettings &graphicsSettings, + LauncherSettings &launcherSettings) : mGameSettings(gameSettings) , mGraphicsSettings(graphicsSettings) + , mLauncherSettings(launcherSettings) { QWidget *centralWidget = new QWidget(this); @@ -132,7 +135,7 @@ void MainDialog::createPages() { mPlayPage = new PlayPage(this); mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this); - mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, this); + mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); @@ -161,18 +164,11 @@ void MainDialog::createPages() bool MainDialog::setup() { - // Setup the Graphics page + // Call this so we can exit on Ogre errors before mainwindow is shown if (!mGraphicsPage->setupOgre()) { return false; } - // Setup the Data Files page - /* - if (!mDataFilesPage->setupDataFiles()) { - return false; - }*/ - - return true; } @@ -184,11 +180,28 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) mPagesWidget->setCurrentIndex(mIconWidget->row(current)); } -void MainDialog::closeEvent(QCloseEvent *event) +void MainDialog::loadSettings() +{ + +} + +void MainDialog::saveSettings() +{ + QString width = QString::number(this->width()); + QString height = QString::number(this->height()); + + mLauncherSettings.setValue(QString("General/MainWindow/width"), width); + mLauncherSettings.setValue(QString("General/MainWindow/height"), height); + + qDebug() << "size: " << width << height; +} + +void MainDialog::writeSettings() { // Now write all config files - mDataFilesPage->writeConfig(); + saveSettings(); mGraphicsPage->saveSettings(); + mDataFilesPage->saveSettings(); QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QDir dir(userPath); @@ -203,7 +216,7 @@ void MainDialog::closeEvent(QCloseEvent *event) Please make sure you have the right permissions \ and try again.
").arg(userPath)); msgBox.exec(); - event->accept(); + return; } } @@ -220,7 +233,7 @@ void MainDialog::closeEvent(QCloseEvent *event) Please make sure you have the right permissions \ and try again.
").arg(file.fileName())); msgBox.exec(); - event->accept(); + return; } QTextStream stream(&file); @@ -242,26 +255,52 @@ void MainDialog::closeEvent(QCloseEvent *event) Please make sure you have the right permissions \ and try again.
").arg(file.fileName())); msgBox.exec(); - event->accept(); + return; } stream.setDevice(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); mGraphicsSettings.writeFile(stream); + file.close(); + // Launcher settings + file.setFileName(userPath + QString("launcher.cfg")); + + if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing Launcher configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0 for writing

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return; + } + + stream.setDevice(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mLauncherSettings.writeFile(stream); + file.close(); +} + +void MainDialog::closeEvent(QCloseEvent *event) +{ + saveSettings(); + writeSettings(); event->accept(); } void MainDialog::play() { // First do a write of all the configs, just to be sure - mDataFilesPage->writeConfig(); + //mDataFilesPage->writeConfig(); //mGraphicsPage->writeConfig(); - - // Save user settings - const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); - mSettings.saveUser(settingspath); + saveSettings(); + writeSettings(); #ifdef Q_OS_WIN QString game = "./openmw.exe"; diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index c9654b874c..7167d101db 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -4,7 +4,6 @@ #include #include -#include class QListWidget; class QListWidgetItem; @@ -19,22 +18,31 @@ class DataFilesPage; class GameSettings; class GraphicsSettings; +class LauncherSettings; class MainDialog : public QMainWindow { Q_OBJECT public: - MainDialog(GameSettings &gameSettings, GraphicsSettings &GraphicsSettings); + MainDialog(GameSettings &gameSettings, + GraphicsSettings &GraphicsSettings, + LauncherSettings &launcherSettings); + + bool setup(); public slots: void changePage(QListWidgetItem *current, QListWidgetItem *previous); void play(); - bool setup(); private: void createIcons(); void createPages(); + + void loadSettings(); + void saveSettings(); + void writeSettings(); + void closeEvent(QCloseEvent *event); QListWidget *mIconWidget; @@ -45,10 +53,10 @@ private: DataFilesPage *mDataFilesPage; Files::ConfigurationManager mCfgMgr; - Settings::Manager mSettings; GameSettings &mGameSettings; GraphicsSettings &mGraphicsSettings; + LauncherSettings &mLauncherSettings; }; diff --git a/apps/launcher/model/datafilesmodel.cpp b/apps/launcher/model/datafilesmodel.cpp index e84dbe0acc..ae59cc3c3f 100644 --- a/apps/launcher/model/datafilesmodel.cpp +++ b/apps/launcher/model/datafilesmodel.cpp @@ -334,6 +334,7 @@ void DataFilesModel::addPlugins(const QString &path) QFileInfo info(dir.absoluteFilePath(path)); EsmFile *file = new EsmFile(path); + try { ESM::ESMReader fileReader; ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString())); @@ -361,7 +362,8 @@ void DataFilesModel::addPlugins(const QString &path) // Put the file in the table - addFile(file); + if (findItem(path) == 0) + addFile(file); } catch(std::runtime_error &e) { // An error occurred while reading the .esp qWarning() << "Error reading esp: " << e.what(); diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 2420c1e6c0..5f0fb77bc4 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -101,7 +101,14 @@ bool GameSettings::readFile(QTextStream &stream) qDebug() << "key: " << key; // There can be multiple data keys if (key == QLatin1String("data")) { - cache.insertMulti(key, value); + // Remove keys from previous config and overwrite them + mSettings.remove(key); + QStringList values = cache.values(key); + if (!values.contains(value)) { + // Do not insert duplicate values + qDebug() << "values does not contain: " << value << values; + cache.insertMulti(key, value); + } } else { cache.insert(key, value); } diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp new file mode 100644 index 0000000000..c189c282fd --- /dev/null +++ b/apps/launcher/settings/launchersettings.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include "launchersettings.hpp" + +LauncherSettings::LauncherSettings() +{ +} + +LauncherSettings::~LauncherSettings() +{ +} + + +bool LauncherSettings::writeFile(QTextStream &stream) +{ + QString sectionPrefix; + QRegExp sectionRe("([^/]+)/(.+)$"); + QMap settings = SettingsBase::getSettings(); + + QMapIterator i(settings); + while (i.hasNext()) { + i.next(); + + QString prefix; + QString key; + + if (sectionRe.exactMatch(i.key())) { + prefix = sectionRe.cap(1); + key = sectionRe.cap(2); + } + + if (sectionPrefix != prefix) { + sectionPrefix = prefix; + stream << "\n[" << prefix << "]\n"; + } + + stream << key << "=" << i.value() << "\n"; + } + + return true; + +} diff --git a/apps/launcher/settings/launchersettings.hpp b/apps/launcher/settings/launchersettings.hpp new file mode 100644 index 0000000000..cf4dd4c9ff --- /dev/null +++ b/apps/launcher/settings/launchersettings.hpp @@ -0,0 +1,16 @@ +#ifndef LAUNCHERSETTINGS_HPP +#define LAUNCHERSETTINGS_HPP + +#include "settingsbase.hpp" + +class LauncherSettings : public SettingsBase> +{ +public: + LauncherSettings(); + ~LauncherSettings(); + + bool writeFile(QTextStream &stream); + +}; + +#endif // LAUNCHERSETTINGS_HPP diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 6b8b52762d..e09ea62038 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -2,6 +2,7 @@ #define SETTINGSBASE_HPP #include +#include #include #include #include @@ -26,6 +27,17 @@ public: mSettings.insert(key, value); } + inline void setMultiValue(const QString &key, const QString &value) + { + mSettings.insertMulti(key, value); + } + + + inline void remove(const QString &key) + { + mSettings.remove(key); + } + Map getSettings() {return mSettings;} bool readFile(QTextStream &stream) @@ -56,11 +68,18 @@ public: if (!sectionPrefix.isEmpty()) key.prepend(sectionPrefix); - // QMap will replace the value if key exists, QMultiMap creates a new one - mCache.insert(key, value); + mSettings.remove(key); + + QStringList values = mCache.values(key); + if (!values.contains(value)) { + // QMap will replace the value if key exists, QMultiMap creates a new one + mCache.insert(key, value); + } } } + qDebug() << "HI THERE! " << mCache; + if (mSettings.isEmpty()) { mSettings = mCache; // This is the first time we read a file return true; diff --git a/apps/launcher/utils/lineedit.cpp b/apps/launcher/utils/lineedit.cpp index dac1964258..b0f3395897 100644 --- a/apps/launcher/utils/lineedit.cpp +++ b/apps/launcher/utils/lineedit.cpp @@ -1,7 +1,8 @@ -#include "lineedit.hpp" #include #include +#include "lineedit.hpp" + LineEdit::LineEdit(QWidget *parent) : QLineEdit(parent) { @@ -13,9 +14,11 @@ LineEdit::LineEdit(QWidget *parent) mClearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }"); mClearButton->hide(); connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear())); - connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateCloseButton(const QString&))); + connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateClearButton(const QString&))); int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); - setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1)); + + setObjectName(QString("LineEdit")); + setStyleSheet(QString("LineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1)); QSize msz = minimumSizeHint(); setMinimumSize(qMax(msz.width(), mClearButton->sizeHint().height() + frameWidth * 2 + 2), qMax(msz.height(), mClearButton->sizeHint().height() + frameWidth * 2 + 2)); @@ -29,9 +32,7 @@ void LineEdit::resizeEvent(QResizeEvent *) (rect().bottom() + 1 - sz.height())/2); } -void LineEdit::updateCloseButton(const QString& text) +void LineEdit::updateClearButton(const QString& text) { mClearButton->setVisible(!text.isEmpty()); } - - diff --git a/apps/launcher/utils/lineedit.hpp b/apps/launcher/utils/lineedit.hpp index 2ed76d6eb7..14bd7b1b4c 100644 --- a/apps/launcher/utils/lineedit.hpp +++ b/apps/launcher/utils/lineedit.hpp @@ -25,7 +25,7 @@ protected: void resizeEvent(QResizeEvent *); private slots: - void updateCloseButton(const QString &text); + void updateClearButton(const QString &text); private: QToolButton *mClearButton; diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp index 8354d4a780..3a75ba417a 100644 --- a/apps/launcher/utils/profilescombobox.cpp +++ b/apps/launcher/utils/profilescombobox.cpp @@ -1,45 +1,94 @@ #include #include #include +#include +#include #include "profilescombobox.hpp" +#include "comboboxlineedit.hpp" ProfilesComboBox::ProfilesComboBox(QWidget *parent) : QComboBox(parent) { mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore - - setEditable(true); + setEditEnabled(true); setValidator(mValidator); setCompleter(0); connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotIndexChanged(int))); - connect(lineEdit(), SIGNAL(returnPressed()), this, - SLOT(slotReturnPressed())); + + } void ProfilesComboBox::setEditEnabled(bool editable) { - if (!editable) + qDebug() << "called"; + if (isEditable() == editable) + return; + + if (!editable) { + disconnect(lineEdit(), SIGNAL(editingFinished()), this, SLOT(slotEditingFinished())); + disconnect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged(QString))); return setEditable(false); + } // Reset the completer and validator setEditable(true); setValidator(mValidator); + + ComboBoxLineEdit *edit = new ComboBoxLineEdit(this); + setLineEdit(edit); setCompleter(0); + + connect(lineEdit(), SIGNAL(editingFinished()), this, + SLOT(slotEditingFinished())); + + connect(lineEdit(), SIGNAL(textChanged(QString)), this, + SLOT(slotTextChanged(QString))); } -void ProfilesComboBox::slotReturnPressed() +void ProfilesComboBox::slotTextChanged(const QString &text) { + QString previous = itemText(currentIndex()); +// lineEdit()->setPalette(QApplication::palette()); + + if (text.isEmpty()) + return; + + if (text == previous) + return; + + qDebug() << "textChanged"; + if (findText(text) != -1) { + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Text,Qt::red); + lineEdit()->setPalette(*palette); + } +} + +void ProfilesComboBox::slotEditingFinished() +{ + qDebug() << "returnpressed"; QString current = currentText(); QString previous = itemText(currentIndex()); + if (current.isEmpty()) + return; + + if (current == previous) + return; + if (findText(current) != -1) return; - setItemText(currentIndex(), current); - emit(profileRenamed(previous, current)); + + if (currentIndex() == -1) { + addItem(currentText()); + } else { + setItemText(currentIndex(), current); + emit(profileRenamed(previous, current)); + } } void ProfilesComboBox::slotIndexChanged(int index) diff --git a/apps/launcher/utils/profilescombobox.hpp b/apps/launcher/utils/profilescombobox.hpp index c7da60d2a5..08ead9a7ab 100644 --- a/apps/launcher/utils/profilescombobox.hpp +++ b/apps/launcher/utils/profilescombobox.hpp @@ -4,7 +4,6 @@ #include class QString; - class QRegExpValidator; class ProfilesComboBox : public QComboBox @@ -19,8 +18,9 @@ signals: void profileRenamed(const QString &oldName, const QString &newName); private slots: - void slotReturnPressed(); + void slotEditingFinished(); void slotIndexChanged(int index); + void slotTextChanged(const QString &text); private: QString mOldProfile; From ba97c8f7d675067b389bbb3e8a127cc67038a7f6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Feb 2013 19:54:32 +0100 Subject: [PATCH 0313/1483] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 5d486c74e7..936f3efd9b 100644 --- a/credits.txt +++ b/credits.txt @@ -26,6 +26,7 @@ gugus / gus Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) +Joel Graff (graffy) Karl-Felix Glatzer (k1ll) lazydev Leon Saunders (emoose) From 3b64389668d181754ec08fc2f4c010bc5a9d3b98 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Tue, 12 Feb 2013 11:14:30 +0400 Subject: [PATCH 0314/1483] BookTextParser: fixed infinitive loop --- apps/openmw/mwgui/formatting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 4090b592d9..1689d2fb1f 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -160,7 +160,7 @@ std::vector BookTextParser::split(std::string text, const int width ++i; } - if (currentHeight > height-spacing) + if (currentHeight > height-spacing && currentText.size() != currentWord.size()) { // remove the last word currentText.erase(currentText.size()-currentWord.size(), currentText.size()); From 03803f19b5ded40a476181189027d3b5fc706ba1 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Tue, 12 Feb 2013 11:22:19 +0400 Subject: [PATCH 0315/1483] BookTextParser: moved to Ogre::UTFString Font height and unicode characters glyph width now accounted correctly. --- apps/openmw/mwgui/formatting.cpp | 168 +++++++++++++++++-------------- apps/openmw/mwgui/formatting.hpp | 2 + 2 files changed, 96 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 1689d2fb1f..c50381a87f 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -6,7 +6,9 @@ #include "../mwworld/ptr.hpp" #include +#include #include +#include using namespace MWGui; @@ -67,118 +69,134 @@ namespace return value; } + + Ogre::UTFString::unicode_char unicodeCharFromChar(char ch) + { + std::string s; + s += ch; + Ogre::UTFString string(s); + return string.getChar(0); + } } -std::vector BookTextParser::split(std::string text, const int width, const int height) +std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) { + using Ogre::UTFString; std::vector result; MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - text = Interpreter::fixDefinesBook(text, interpreterContext); + utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); - boost::algorithm::replace_all(text, "
", "\n"); - boost::algorithm::replace_all(text, "

", "\n\n"); + boost::algorithm::replace_all(utf8Text, "
", "\n"); + boost::algorithm::replace_all(utf8Text, "

", "\n\n"); + UTFString text(utf8Text); const int spacing = 48; - while (text.size() > 0) + const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); + const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); + const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); + + while (!text.empty()) { // read in characters until we have exceeded the size, or run out of text int currentWidth = 0; int currentHeight = 0; - std::string currentText; - std::string currentWord; - unsigned int i=0; - while (currentHeight <= height-spacing && i', i) == std::string::npos) + const size_t tagStart = index + 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == UTFString::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); - if (text.size() > i+4 && text.substr(i, 4) == "', i)-i), false); - currentHeight += (mHeight-h); + const int h = mHeight; + parseImage(tag, false); + currentHeight += (mHeight - h); currentWidth = 0; } - else if (text.size() > i+5 && text.substr(i, 5) == "', i)-i)); - currentHeight += 18; // keep this in sync with the font size + parseFont(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } currentWidth = 0; } - else if (text.size() > i+4 && text.substr(i, 4) == "', i)-i)); - currentHeight += 18; // keep this in sync with the font size - currentWidth = 0; + parseDiv(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } } - - currentText += text.substr(i, text.find('>', i)-i+1); - i = text.find('>', i); + index = tagEnd; } - else if (text[i] == '\n') + else if (ch == NEWLINE) { - currentHeight += 18; // keep this in sync with the font size + currentHeight += currentFontHeight(); currentWidth = 0; - currentWord = ""; - currentText += text[i]; + currentWordStart = index; } - else if (text[i] == ' ') + else if (ch == SPACE) { currentWidth += 3; // keep this in sync with the font's SpaceWidth property - currentWord = ""; - currentText += text[i]; + currentWordStart = index; } else { - currentWidth += - MyGUI::FontManager::getInstance().getByName (mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont) - ->getGlyphInfo(static_cast(text[i]))->width; - currentWord += text[i]; - currentText += text[i]; + currentWidth += widthForCharGlyph(ch); } if (currentWidth > width) { - currentHeight += 18; // keep this in sync with the font size + currentHeight += currentFontHeight(); currentWidth = 0; - // add size of the current word - unsigned int j=0; - while (jgetGlyphInfo(static_cast(currentWord[j]))->width; - ++j; - } + UTFString word = text.substr(currentWordStart, index - currentWordStart); + for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) + currentWidth += widthForCharGlyph(it.getCharacter()); } - - ++i; - } - if (currentHeight > height-spacing && currentText.size() != currentWord.size()) - { - // remove the last word - currentText.erase(currentText.size()-currentWord.size(), currentText.size()); + index += UTFString::_utf16_char_length(ch); } + const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) + ? currentWordStart : index; - result.push_back(currentText); - text.erase(0, currentText.size()); + result.push_back(text.substr(0, pageEnd).asUTF8()); + text.erase(0, pageEnd); } return result; } +float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const +{ + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName) + ->getGlyphInfo(unicodeChar)->width; +} + +float BookTextParser::currentFontHeight() const +{ + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); +} + MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor text = Interpreter::fixDefinesBook(text, interpreterContext); - mParent = parent; mWidth = width; mHeight = 0; @@ -193,8 +211,8 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co boost::algorithm::replace_all(text, "

", "\n\n"); // remove leading newlines - //while (text[0] == '\n') - // text.erase(0); +// while (text[0] == '\n') +// text.erase(0); // remove trailing " if (text[text.size()-1] == '\"') @@ -279,28 +297,30 @@ void BookTextParser::parseSubText(std::string text) { if (text[0] == '<') { - if (text.find('>') == std::string::npos) + const size_t tagStart = 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == std::string::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart); - if (text.size() > 4 && text.substr(0, 4) == "'))); - else if (text.size() > 5 && text.substr(0, 5) == "'))); - else if (text.size() > 4 && text.substr(0, 4) == "'))); + if (boost::algorithm::starts_with(tag, "IMG")) + parseImage(tag); + if (boost::algorithm::starts_with(tag, "FONT")) + parseFont(tag); + if (boost::algorithm::starts_with(tag, "DOV")) + parseDiv(tag); - text.erase(0, text.find('>')+1); + text.erase(0, tagEnd + 1); } - bool tagFound = false; + size_t tagStart = std::string::npos; std::string realText; // real text, without tags - unsigned int i=0; - for (; isetSize(box->getSize().width, box->getTextSize().height); mHeight += box->getTextSize().height; - if (tagFound) + if (tagStart != std::string::npos) { - parseSubText(text.substr(i, text.size())); + parseSubText(text.substr(tagStart, text.size())); } } diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index a1e115491d..ab1ee3af4d 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -40,6 +40,8 @@ namespace MWGui std::vector split(std::string text, const int width, const int height); protected: + float widthForCharGlyph(unsigned unicodeChar) const; + float currentFontHeight() const; void parseSubText(std::string text); void parseImage(std::string tag, bool createWidget=true); From 7d7a1119daccbf4a342555a3395c00fbd5e9f817 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Tue, 12 Feb 2013 11:49:20 +0400 Subject: [PATCH 0316/1483] Fixed book text misalignment, at least in some cases https://bugs.openmw.org/issues/284 --- apps/openmw/mwgui/formatting.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index c50381a87f..7f28e9e17d 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -87,6 +87,7 @@ std::vector BookTextParser::split(std::string utf8Text, const int w MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); + boost::algorithm::replace_all(utf8Text, "\n", ""); boost::algorithm::replace_all(utf8Text, "
", "\n"); boost::algorithm::replace_all(utf8Text, "

", "\n\n"); @@ -207,6 +208,7 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); } + boost::algorithm::replace_all(text, "\n", ""); boost::algorithm::replace_all(text, "
", "\n"); boost::algorithm::replace_all(text, "

", "\n\n"); From f9a0a19ee1303ac3242695fcdf329169d6410523 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 12 Feb 2013 13:23:25 +0100 Subject: [PATCH 0317/1483] Fix a small issue in the windows installer, also added the OpenMW version to the installed package name --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 577b6f6b2d..cfd1c7dd39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -391,11 +391,11 @@ if(WIN32) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") SET(CPACK_GENERATOR "NSIS") - SET(CPACK_PACKAGE_NAME "OpenMW") + SET(CPACK_PACKAGE_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_PACKAGE_VENDOR "OpenMW.org") SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) - SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO}) + SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;omwlauncher;OpenMW Launcher") SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'") From 0ae01794f1e1b106bf7fbfe592aade099036a285 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 12 Feb 2013 13:57:16 +0100 Subject: [PATCH 0318/1483] Fixed build errors in OpenCS --- apps/opencs/model/world/record.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 229985a8a2..14f63c155d 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -3,19 +3,19 @@ CSMWorld::RecordBase::~RecordBase() {} -bool CSMWorld::RecordBase::RecordBase::isDeleted() const +bool CSMWorld::RecordBase::isDeleted() const { return mState==State_Deleted || mState==State_Erased; } -bool CSMWorld::RecordBase::RecordBase::isErased() const +bool CSMWorld::RecordBase::isErased() const { return mState==State_Erased; } -bool CSMWorld::RecordBase::RecordBase::isModified() const +bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; } \ No newline at end of file From bbb845824d90a87661df67366f8e8129b68d25e2 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 12 Feb 2013 13:59:24 +0100 Subject: [PATCH 0319/1483] Added typedef for ssize_t in windows and fixed a use of __PRETTY_FUNCTION__ --- apps/openmw/mwrender/videoplayer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index baec2f7409..b710225042 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -17,6 +17,11 @@ #include "../mwsound/sound_decoder.hpp" #include "../mwsound/sound.hpp" +#ifdef _WIN32 +#include + +typedef SSIZE_T ssize_t; +#endif namespace MWRender { @@ -361,7 +366,11 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder } void open(const std::string&) +#ifdef _WIN32 + { fail(std::string("Invalid call to ")+__FUNCSIG__); } +#else { fail(std::string("Invalid call to ")+__PRETTY_FUNCTION__); } +#endif void close() { } From d213ff680ff5e71874ef33065d38f1285d68e67a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Feb 2013 20:55:45 +0100 Subject: [PATCH 0320/1483] Disabled terrain LOD --- apps/openmw/mwrender/terrain.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 2c2e9e6fcf..df8d34e74c 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -40,9 +40,9 @@ namespace MWRender ->getActiveProfile(); mActiveProfile = static_cast(activeProfile); - //The pixel error should be as high as possible without it being noticed - //as it governs how fast mesh quality decreases. - mTerrainGlobals->setMaxPixelError(8); + // We don't want any pixel error at all. Really, LOD makes no sense here - morrowind uses 65x65 verts in one cell, + // so applying LOD is most certainly slower than doing no LOD at all. + mTerrainGlobals->setMaxPixelError(0); mTerrainGlobals->setLayerBlendMapSize(32); From de90b911c9d729fc4abe856fed525d565beb1c71 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Feb 2013 20:56:00 +0100 Subject: [PATCH 0321/1483] Near clip plane corrections --- apps/openmw/mwrender/refraction.cpp | 36 ++++++++++++++++++++++++++--- apps/openmw/mwrender/refraction.hpp | 11 ++++++++- apps/openmw/mwrender/water.cpp | 9 ++++++-- apps/openmw/mwrender/water.hpp | 1 + 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 85642bc088..05229da1d1 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "renderconst.hpp" @@ -14,9 +15,13 @@ namespace MWRender Refraction::Refraction(Ogre::Camera *parentCamera) : mParentCamera(parentCamera) + , mRenderActive(false) + , mIsUnderwater(false) { mCamera = mParentCamera->getSceneManager()->createCamera("RefractionCamera"); + mParentCamera->getSceneManager()->addRenderQueueListener(this); + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("WaterRefraction", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); @@ -24,7 +29,7 @@ namespace MWRender Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); - vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain); + vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); vp->setMaterialScheme("water_reflection"); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); @@ -47,17 +52,42 @@ namespace MWRender mCamera->setAspectRatio(mParentCamera->getAspectRatio()); mCamera->setFOVy(mParentCamera->getFOVy()); - mCamera->enableCustomNearClipPlane(mNearClipPlane); + mRenderActive = true; } void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { - + mRenderActive = false; } void Refraction::setHeight(float height) { mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,1,0), -(height + 5)); + mNearClipPlaneUnderwater = Ogre::Plane( Ogre::Vector3(0,1,0), height - 5); + } + + void Refraction::setViewportBackground (Ogre::ColourValue colour) + { + mRenderTarget->getViewport (0)->setBackgroundColour (colour); + } + + void Refraction::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) + { + // We don't want the sky to get clipped by custom near clip plane (the water plane) + if (queueGroupId < 20 && mRenderActive) + { + mCamera->disableCustomNearClipPlane(); + Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + } + } + + void Refraction::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) + { + if (queueGroupId < 20 && mRenderActive) + { + mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); + Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + } } } diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp index e3777d9cf1..6b3c487c11 100644 --- a/apps/openmw/mwrender/refraction.hpp +++ b/apps/openmw/mwrender/refraction.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace Ogre { @@ -13,7 +14,7 @@ namespace Ogre namespace MWRender { - class Refraction : public Ogre::RenderTargetListener + class Refraction : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener { public: @@ -23,12 +24,20 @@ namespace MWRender void setHeight (float height); void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void setViewportBackground(Ogre::ColourValue colour); + void setUnderwater(bool underwater) {mIsUnderwater = underwater;} + + void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); + void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); private: Ogre::Camera* mParentCamera; Ogre::Camera* mCamera; Ogre::RenderTarget* mRenderTarget; Ogre::Plane mNearClipPlane; + Ogre::Plane mNearClipPlaneUnderwater; + bool mRenderActive; + bool mIsUnderwater; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8678295649..f31dca08cf 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -124,8 +124,8 @@ void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::St { if (queueGroupId < 20 && mRenderActive) { - if (!mIsUnderwater) - mCamera->enableCustomNearClipPlane(mErrorPlane); + // this trick does not seem to work well for extreme angles + mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); } } @@ -159,6 +159,7 @@ void PlaneReflection::setHeight (float height) { mWaterPlane = Plane(Ogre::Vector3(0,1,0), height); mErrorPlane = Plane(Ogre::Vector3(0,1,0), height - 5); + mErrorPlaneUnderwater = Plane(Ogre::Vector3(0,-1,0), -height - 5); } void PlaneReflection::setActive (bool active) @@ -348,6 +349,8 @@ Water::updateUnderwater(bool underwater) if (mReflection) mReflection->setUnderwater (mIsUnderwater); + if (mRefraction) + mRefraction->setUnderwater (mIsUnderwater); updateVisible(); } @@ -377,6 +380,8 @@ void Water::setViewportBackground(const ColourValue& bg) { if (mReflection) mReflection->setViewportBackground(bg); + if (mRefraction) + mRefraction->setViewportBackground(bg); } void Water::updateVisible() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index cf181674a5..9aa18f008a 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -89,6 +89,7 @@ namespace MWRender { SkyManager* mSky; Ogre::Plane mWaterPlane; Ogre::Plane mErrorPlane; + Ogre::Plane mErrorPlaneUnderwater; bool mRenderActive; }; From 5b2ca6fa7d3a6f61f6a5b60bb1cd1144ffd04a8f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Feb 2013 00:43:29 -0800 Subject: [PATCH 0322/1483] Don't complain about RootCollisionNode, it's handled in nifbullet --- components/nifogre/ogre_nif_loader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5f7e686a09..e276092c73 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -328,7 +328,9 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro ctrl = ctrl->next; } - if(!(node->recType == Nif::RC_NiNode)) + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); Nif::ExtraPtr e = node->extra; From da5f11700f8e6603d09a04f868fe3de112beacc4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Feb 2013 00:45:00 -0800 Subject: [PATCH 0323/1483] Warn about unhandled node types before the controllers --- components/nifogre/ogre_nif_loader.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e276092c73..c52a73e1c1 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -318,6 +318,11 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro bone->setScale(Ogre::Vector3(node->trafo.scale)); bone->setBindingPose(); + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + )) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { @@ -328,11 +333,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro ctrl = ctrl->next; } - if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ - )) - warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); - Nif::ExtraPtr e = node->extra; while(!e.empty()) { From 6a49ea9b4fd5726f07c17db95c620a1059f78d1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Feb 2013 18:39:36 +0100 Subject: [PATCH 0324/1483] Cleaning out some old bits --- apps/openmw/mwbase/inputmanager.hpp | 3 -- apps/openmw/mwgui/settingswindow.cpp | 6 +++ apps/openmw/mwinput/inputmanagerimp.cpp | 17 ++------- apps/openmw/mwinput/inputmanagerimp.hpp | 4 -- apps/openmw/mwrender/refraction.cpp | 6 +-- apps/openmw/mwrender/refraction.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 45 +++-------------------- apps/openmw/mwrender/renderingmanager.hpp | 2 - apps/openmw/mwrender/water.cpp | 2 - 9 files changed, 16 insertions(+), 70 deletions(-) diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index f69e1a1529..8293cbfa7e 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -39,9 +39,6 @@ namespace MWBase virtual int getNumActions() = 0; virtual void enableDetectingBindingMode (int action) = 0; virtual void resetToDefaultBindings() = 0; - - virtual void create () = 0; - virtual void destroy () = 0; }; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index eaea022c0c..73f2f6c8ae 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -370,6 +370,12 @@ namespace MWGui apply(); } } + else if (_sender == mVSyncButton) + { + Settings::Manager::setBool("vsync", "Video", newState); + MWBase::Environment::get().getWindowManager()-> + messageBox("VSync will be applied after a restart", std::vector()); + } else { if (_sender == mVSyncButton) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 00849503c6..0934d87639 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -53,14 +53,6 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) - { - create(); - - changeInputMode(false); - } - - - void InputManager::create() { Ogre::RenderWindow* window = mOgre.getWindow (); size_t windowHnd; @@ -139,9 +131,11 @@ namespace MWInput mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; + + changeInputMode(false); } - void InputManager::destroy() + InputManager::~InputManager() { mInputCtrl->save (mUserFile); @@ -152,11 +146,6 @@ namespace MWInput OIS::InputManager::destroyInputSystem(mInputManager); } - InputManager::~InputManager() - { - destroy(); - } - void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { if (mDragDrop) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 7be35ee0b6..3be669621a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -153,10 +153,6 @@ namespace MWInput std::map mControlSwitch; - public: - virtual void create(); - virtual void destroy(); - private: void adjustMouseRegion(int width, int height); diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 05229da1d1..e6b6e3baad 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -31,6 +31,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); vp->setMaterialScheme("water_reflection"); + vp->setBackgroundColour (Ogre::ColourValue(0.0078, 0.0576, 0.150)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } @@ -66,11 +67,6 @@ namespace MWRender mNearClipPlaneUnderwater = Ogre::Plane( Ogre::Vector3(0,1,0), height - 5); } - void Refraction::setViewportBackground (Ogre::ColourValue colour) - { - mRenderTarget->getViewport (0)->setBackgroundColour (colour); - } - void Refraction::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) { // We don't want the sky to get clipped by custom near clip plane (the water plane) diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp index 6b3c487c11..de47d6e43b 100644 --- a/apps/openmw/mwrender/refraction.hpp +++ b/apps/openmw/mwrender/refraction.hpp @@ -24,7 +24,6 @@ namespace MWRender void setHeight (float height); void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void setViewportBackground(Ogre::ColourValue colour); void setUnderwater(bool underwater) {mIsUnderwater = underwater;} void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index afbdbb06f3..ce48284e09 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -46,8 +46,12 @@ namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) - : mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0), mPhysicsEngine(engine), - mRecreateWindowInNextFrame(false) + : mRendering(_rend) + , mObjects(mRendering) + , mActors(mRendering) + , mAmbientMode(0) + , mSunEnabled(0) + , mPhysicsEngine(engine) { // select best shader mode bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); @@ -324,33 +328,6 @@ RenderingManager::moveObjectToCell( void RenderingManager::update (float duration, bool paused) { - if (mRecreateWindowInNextFrame) - { - mRecreateWindowInNextFrame = false; - - mRendering.removeWindowEventListener(this); - mRendering.getWindow()->removeListener(this); - MWBase::Environment::get().getInputManager()->destroy(); - - OEngine::Render::WindowSettings windowSettings; - windowSettings.fullscreen = Settings::Manager::getBool("fullscreen", "Video"); - windowSettings.window_x = Settings::Manager::getInt("resolution x", "Video"); - windowSettings.window_y = Settings::Manager::getInt("resolution y", "Video"); - windowSettings.vsync = Settings::Manager::getBool("vsync", "Video"); - std::string aa = Settings::Manager::getString("antialiasing", "Video"); - windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; - mRendering.recreateWindow("OpenMW", windowSettings); - - MWBase::Environment::get().getInputManager()->create(); - mRendering.setWindowEventListener (this); - mRendering.getWindow()->addListener(this); - - // this is necessary, otherwise it would just endlessly wait for the last query and it would never return - delete mOcclusionQuery; - mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); - } - - Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -784,7 +761,6 @@ Compositors* RenderingManager::getCompositors() void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) { bool changeRes = false; - bool recreateWindow = false; bool rebuild = false; // rebuild static geometry (necessary after any material changes) for (Settings::CategorySettingVector::const_iterator it=settings.begin(); it != settings.end(); ++it) @@ -803,8 +779,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec || it->second == "resolution y" || it->second == "fullscreen")) changeRes = true; - else if (it->first == "Video" && it->second == "vsync") - recreateWindow = true; else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); else if ((it->second == "texture filtering" && it->first == "General") @@ -876,13 +850,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } - if (recreateWindow) - { - mRecreateWindowInNextFrame = true; - // We can not do this now, because this might get triggered from the input listener - // and destroying/recreating the input system at that point would cause a crash - } - if (mWater) mWater->processChangedSettings(settings); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 670f3dc85e..71ac742c2a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -260,8 +260,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList MWRender::Compositors* mCompositors; VideoPlayer* mVideoPlayer; - - bool mRecreateWindowInNextFrame; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f31dca08cf..3b8705ac56 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -380,8 +380,6 @@ void Water::setViewportBackground(const ColourValue& bg) { if (mReflection) mReflection->setViewportBackground(bg); - if (mRefraction) - mRefraction->setViewportBackground(bg); } void Water::updateVisible() From 5d1bede9e50c13d72f548f23d3b5e8da60b79119 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Thu, 14 Feb 2013 11:20:47 +0100 Subject: [PATCH 0325/1483] Forgot to add two files --- apps/launcher/utils/comboboxlineedit.cpp | 35 ++++++++++++++++++++++++ apps/launcher/utils/comboboxlineedit.hpp | 35 ++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 apps/launcher/utils/comboboxlineedit.cpp create mode 100644 apps/launcher/utils/comboboxlineedit.hpp diff --git a/apps/launcher/utils/comboboxlineedit.cpp b/apps/launcher/utils/comboboxlineedit.cpp new file mode 100644 index 0000000000..4d62e1399a --- /dev/null +++ b/apps/launcher/utils/comboboxlineedit.cpp @@ -0,0 +1,35 @@ +#include +#include + +#include "comboboxlineedit.hpp" + +ComboBoxLineEdit::ComboBoxLineEdit(QWidget *parent) + : QLineEdit(parent) +{ + mClearButton = new QToolButton(this); + QPixmap pixmap(":images/clear.png"); + mClearButton->setIcon(QIcon(pixmap)); + mClearButton->setIconSize(pixmap.size()); + mClearButton->setCursor(Qt::ArrowCursor); + mClearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }"); + mClearButton->hide(); + connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear())); + connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateClearButton(const QString&))); + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + + setObjectName(QString("ComboBoxLineEdit")); + setStyleSheet(QString("ComboBoxLineEdit { background-color: transparent; padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1)); +} + +void ComboBoxLineEdit::resizeEvent(QResizeEvent *) +{ + QSize sz = mClearButton->sizeHint(); + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + mClearButton->move(rect().right() - frameWidth - sz.width(), + (rect().bottom() + 1 - sz.height())/2); +} + +void ComboBoxLineEdit::updateClearButton(const QString& text) +{ + mClearButton->setVisible(!text.isEmpty()); +} diff --git a/apps/launcher/utils/comboboxlineedit.hpp b/apps/launcher/utils/comboboxlineedit.hpp new file mode 100644 index 0000000000..ba10731ae3 --- /dev/null +++ b/apps/launcher/utils/comboboxlineedit.hpp @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (c) 2007 Trolltech ASA +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#ifndef LINEEDIT_H +#define LINEEDIT_H + +#include + +class QToolButton; + +class ComboBoxLineEdit : public QLineEdit +{ + Q_OBJECT + +public: + ComboBoxLineEdit(QWidget *parent = 0); + +protected: + void resizeEvent(QResizeEvent *); + +private slots: + void updateClearButton(const QString &text); + +private: + QToolButton *mClearButton; +}; + +#endif // LIENEDIT_H + From 492e0f2ccfbf9b069346e738f9145359a036335e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Feb 2013 19:45:07 +0100 Subject: [PATCH 0326/1483] Switched objects shaders to vertex lighting, to accomodate badly placed lights in morrowind. Fixed a very obvious land <-> water seam. --- files/materials/objects.shader | 83 +++++++++++++++++++++++++++++++--- files/materials/terrain.shader | 13 ++---- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 1e9c4a3343..af596b779a 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -22,6 +22,8 @@ #define HAS_VERTEXCOLOR @shPropertyBool(has_vertex_colour) +#define VERTEX_LIGHTING 1 + #ifdef SH_VERTEX_SHADER // ------------------------------------- VERTEX --------------------------------------- @@ -42,8 +44,24 @@ #if HAS_VERTEXCOLOR shColourInput(float4) +#if !VERTEX_LIGHTING shOutput(float4, colourPassthrough) #endif +#endif + +#if VERTEX_LIGHTING + shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) + shUniform(float4, lightPosition[8]) @shAutoConstant(lightPosition, light_position_object_space_array, 8) + shUniform(float4, lightDiffuse[8]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, 8) + shUniform(float4, lightAttenuation[8]) @shAutoConstant(lightAttenuation, light_attenuation_array, 8) + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) +#if !HAS_VERTEXCOLOUR + shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) +#endif + shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) + shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + +#endif #if SHADOWS shOutput(float4, lightSpacePos0) @@ -58,6 +76,11 @@ @shEndForeach shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) #endif + +#if VERTEX_LIGHTING + shOutput(float3, lightResult) + shOutput(float3, directionalResult) +#endif SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); @@ -74,7 +97,7 @@ objSpacePositionPassthrough = shInputPosition.xyz; #endif -#if HAS_VERTEXCOLOR +#if HAS_VERTEXCOLOR && !VERTEX_LIGHTING colourPassthrough = colour; #endif @@ -86,6 +109,36 @@ @shForeach(3) lightSpacePos@shIterator = shMatrixMult(texViewProjMatrix@shIterator, wPos); @shEndForeach +#endif + + +#if VERTEX_LIGHTING + float3 lightDir; + float d; + + @shForeach(@shGlobalSettingString(num_lights)) + lightDir = lightPosition[@shIterator].xyz - (shInputPosition.xyz * lightPosition[@shIterator].w); + d = length(lightDir); + lightDir = normalize(lightDir); + + lightResult += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz + * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * max(dot(normalize(normal.xyz), normalize(lightDir)), 0); + +#if @shIterator == 0 + directionalResult = lightResult; +#endif + + @shEndForeach + +#if HAS_VERTEXCOLOR + // ambient vertex colour tracking, FFP behaviour + lightResult += lightAmbient.xyz * colour.xyz + materialEmissive.xyz; + +#else + lightResult += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; +#endif + #endif } @@ -115,25 +168,29 @@ #if LIGHTING shInput(float3, normalPassthrough) shInput(float3, objSpacePositionPassthrough) - shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) #if !HAS_VERTEXCOLOR shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) #endif shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) +#if !VERTEX_LIGHTING + @shForeach(@shGlobalSettingString(num_lights)) shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) shUniform(float4, lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) shUniform(float4, lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) @shEndForeach #endif + +#endif #if FOG shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) #endif -#if HAS_VERTEXCOLOR +#if HAS_VERTEXCOLOR && !VERTEX_LIGHTING shInput(float4, colourPassthrough) #endif @@ -175,6 +232,11 @@ shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #endif +#if VERTEX_LIGHTING + shInput(float3, lightResult) + shInput(float3, directionalResult) +#endif + SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV); @@ -187,9 +249,9 @@ #if HAS_VERTEXCOLOR // ambient vertex colour tracking, FFP behaviour - float3 ambient = colourPassthrough.xyz * lightAmbient.xyz; + //float3 ambient = colourPassthrough.xyz * lightAmbient.xyz; #else - float3 ambient = materialAmbient.xyz * lightAmbient.xyz; + //float3 ambient = materialAmbient.xyz * lightAmbient.xyz; #endif // shadows only for the first (directional) light @@ -228,6 +290,7 @@ caustics = float3(1,1,1); #endif +#if !VERTEX_LIGHTING @shForeach(@shGlobalSettingString(num_lights)) @@ -253,9 +316,16 @@ @shEndForeach - shOutputColour(0).xyz *= (ambient + diffuse + materialEmissive.xyz); + lightResult = (ambient + diffuse + materialEmissive.xyz); #endif +#if SHADOWS + shOutputColour(0).xyz *= (lightResult - directionalResult * (1.0-shadow)); +#else + shOutputColour(0).xyz *= (lightResult); +#endif + +#endif // IF LIGHTING #if HAS_VERTEXCOLOR && !LIGHTING shOutputColour(0).xyz *= colourPassthrough.xyz; @@ -303,7 +373,6 @@ #if MRT shOutputColour(1) = float4(depthPassthrough / far,1,1,1); #endif - } #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 9b891e1e80..d62bb4035e 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -32,7 +32,7 @@ @shAllocatePassthrough(2, UV) #if LIGHTING -@shAllocatePassthrough(3, objSpacePosition) +@shAllocatePassthrough(3, worldPos) #endif #if SHADOWS @@ -101,7 +101,7 @@ @shPassthroughAssign(UV, uv0); #if LIGHTING - @shPassthroughAssign(objSpacePosition, shInputPosition.xyz); + @shPassthroughAssign(worldPos, worldPos.xyz); #endif #if SHADOWS @@ -162,7 +162,7 @@ #if LIGHTING shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) @shForeach(@shGlobalSettingString(terrain_num_lights)) - shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) + shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position, @shIterator) shUniform(float4, lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) shUniform(float4, lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) @shEndForeach @@ -213,7 +213,7 @@ float2 UV = @shPassthroughReceive(UV); #if LIGHTING - float3 objSpacePosition = @shPassthroughReceive(objSpacePosition); + float3 worldPos = @shPassthroughReceive(worldPos); float3 normal = shSample(normalMap, UV).rgb * 2 - 1; normal = normalize(normal); @@ -222,9 +222,6 @@ float3 caustics = float3(1,1,1); -#if (UNDERWATER) || (FOG) - float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePosition,1)).xyz; -#endif #if UNDERWATER @@ -306,7 +303,7 @@ @shForeach(@shGlobalSettingString(terrain_num_lights)) - lightDir = lightPosObjSpace@shIterator.xyz - (objSpacePosition.xyz * lightPosObjSpace@shIterator.w); + lightDir = lightPosObjSpace@shIterator.xyz - (worldPos.xyz * lightPosObjSpace@shIterator.w); d = length(lightDir); From 7604fb51b66a63a1f9b0256447982b1e65024b81 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Feb 2013 23:17:21 +0100 Subject: [PATCH 0327/1483] CG no longer listed in the settings if the plugin isn't loaded. --- apps/openmw/mwgui/settingswindow.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 73f2f6c8ae..54c2ef197f 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -77,6 +78,17 @@ namespace { return (Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") != std::string::npos) ? "glsl" : "hlsl"; } + + bool cgAvailable () + { + Ogre::Root::PluginInstanceList list = Ogre::Root::getSingleton ().getInstalledPlugins (); + for (Ogre::Root::PluginInstanceList::const_iterator it = list.begin(); it != list.end(); ++it) + { + if ((*it)->getName() == "Cg Program Manager") + return true; + } + return false; + } } namespace MWGui @@ -428,7 +440,7 @@ namespace MWGui { val = hlslGlsl(); } - else + else if (cgAvailable ()) val = "cg"; static_cast(_sender)->setCaption(val); From 1b9cf8c23fbcbc6591bcd45bd29fb6a34f5007c7 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Fri, 15 Feb 2013 01:20:48 +0100 Subject: [PATCH 0328/1483] More work on integrating the settings parser, profiles are handled correctly --- apps/launcher/datafilespage.cpp | 71 +++++++++++++++++---- apps/launcher/settings/launchersettings.cpp | 54 ++++++++++++++++ apps/launcher/settings/launchersettings.hpp | 3 + apps/launcher/settings/settingsbase.hpp | 16 +++-- apps/launcher/utils/profilescombobox.cpp | 28 ++++---- 5 files changed, 140 insertions(+), 32 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 12323b1f19..678f8cc3c2 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -293,22 +293,77 @@ void DataFilesPage::setupDataFiles() mPluginsModel->addPlugins(dataLocal); } + QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); + QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + + mProfilesComboBox->addItems(profiles); + + // Add the current profile if empty + if (mProfilesComboBox->findText(profile) == -1) + mProfilesComboBox->addItem(profile); + + if (mProfilesComboBox->findText(QString("Default")) == -1) + mProfilesComboBox->addItem(QString("Default")); + + if (profile.isEmpty()) { + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(QString("Default"))); + } else { + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); + } + loadSettings(); } void DataFilesPage::loadSettings() { qDebug() << "load settings"; + QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + + qDebug() << mLauncherSettings.values(QString("Profiles/Default"), Qt::MatchStartsWith); + + + + if (profile.isEmpty()) + return; + + + mMastersModel->uncheckAll(); + mPluginsModel->uncheckAll(); + + QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly); + QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly); + qDebug() << "masters to check " << plugins; + + foreach (const QString &master, masters) { + QModelIndex index = mMastersModel->indexFromItem(mMastersModel->findItem(master)); + if (index.isValid()) + mMastersModel->setCheckState(index, Qt::Checked); + } + + foreach (const QString &plugin, plugins) { + QModelIndex index = mPluginsModel->indexFromItem(mPluginsModel->findItem(plugin)); + if (index.isValid()) + mPluginsModel->setCheckState(index, Qt::Checked); + } } void DataFilesPage::saveSettings() { QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + + if (profile.isEmpty()) { + profile = mProfilesComboBox->currentText(); + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), profile); + } + qDebug() << "save settings" << profile; + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); QStringList items = mMastersModel->checkedItems(); foreach(const QString &master, items) { + qDebug() << "setting " << master; mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), master); } @@ -482,17 +537,11 @@ void DataFilesPage::writeConfig(QString profile) void DataFilesPage::newProfile() { -// if (mNewProfileDialog->exec() == QDialog::Accepted) { - -// const QString text = mNewProfileDialog->lineEdit()->text(); -// mProfilesComboBox->addItem(text); -// mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); -// } - - mDeleteProfileAction->setEnabled(false); - mProfilesComboBox->setCurrentIndex(-1); - mProfilesComboBox->setEditEnabled(true); - mProfilesComboBox->lineEdit()->setFocus(); + if (mNewProfileDialog->exec() == QDialog::Accepted) { + QString profile = mNewProfileDialog->lineEdit()->text(); + mProfilesComboBox->addItem(profile); + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); + } } void DataFilesPage::updateOkButton(const QString &text) diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index c189c282fd..07502ea027 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -13,6 +13,60 @@ LauncherSettings::~LauncherSettings() { } +QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags) +{ + QMap settings = SettingsBase::getSettings(); + + if (flags == Qt::MatchExactly) + return settings.values(key); + + QStringList result; + + if (flags == Qt::MatchStartsWith) { + QStringList keys = settings.keys(); + + foreach (const QString ¤tKey, keys) { + qDebug() << "key is: " << currentKey << "value: " << settings.value(currentKey); + if (currentKey.startsWith(key)) + result.append(settings.value(currentKey)); + } + } + + return result; +} + +QStringList LauncherSettings::subKeys(const QString &key) +{ + QMap settings = SettingsBase::getSettings(); + QStringList keys = settings.keys(); + + QRegExp keyRe("(.+)/"); + + QStringList result; + + foreach (const QString ¤tKey, keys) { + qDebug() << "key is: " << currentKey; + if (keyRe.indexIn(currentKey) != -1) { + qDebug() << "text: " << keyRe.cap(1) << keyRe.cap(2); + + QString prefixedKey = keyRe.cap(1); + if(prefixedKey.startsWith(key)) { + + QString subKey = prefixedKey.remove(key); + if (!subKey.isEmpty()) + result.append(subKey); + //qDebug() << keyRe.cap(2).simplified(); + } + } else { + qDebug() << "no match"; + } + } + + result.removeDuplicates(); + qDebug() << result; + + return result; +} bool LauncherSettings::writeFile(QTextStream &stream) { diff --git a/apps/launcher/settings/launchersettings.hpp b/apps/launcher/settings/launchersettings.hpp index cf4dd4c9ff..d78a75d458 100644 --- a/apps/launcher/settings/launchersettings.hpp +++ b/apps/launcher/settings/launchersettings.hpp @@ -9,6 +9,9 @@ public: LauncherSettings(); ~LauncherSettings(); + QStringList subKeys(const QString &key); + QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly); + bool writeFile(QTextStream &stream); }; diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index e09ea62038..361884da6f 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -24,12 +24,20 @@ public: inline void setValue(const QString &key, const QString &value) { - mSettings.insert(key, value); + QStringList values = mSettings.values(key); + if (!values.contains(value)) + mSettings.insert(key, value); } inline void setMultiValue(const QString &key, const QString &value) { - mSettings.insertMulti(key, value); + QStringList values = mSettings.values(key); + if (!values.contains(value)) { + qDebug() << "inserting " << value; + mSettings.insertMulti(key, value); + } else { + qDebug() << "not inserting " << value; + } } @@ -73,13 +81,11 @@ public: QStringList values = mCache.values(key); if (!values.contains(value)) { // QMap will replace the value if key exists, QMultiMap creates a new one - mCache.insert(key, value); + mCache.insertMulti(key, value); } } } - qDebug() << "HI THERE! " << mCache; - if (mSettings.isEmpty()) { mSettings = mCache; // This is the first time we read a file return true; diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp index 3a75ba417a..a2c8668cb5 100644 --- a/apps/launcher/utils/profilescombobox.cpp +++ b/apps/launcher/utils/profilescombobox.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "profilescombobox.hpp" #include "comboboxlineedit.hpp" @@ -18,12 +19,11 @@ ProfilesComboBox::ProfilesComboBox(QWidget *parent) : connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotIndexChanged(int))); - + setInsertPolicy(QComboBox::NoInsert); } void ProfilesComboBox::setEditEnabled(bool editable) { - qDebug() << "called"; if (isEditable() == editable) return; @@ -50,29 +50,25 @@ void ProfilesComboBox::setEditEnabled(bool editable) void ProfilesComboBox::slotTextChanged(const QString &text) { - QString previous = itemText(currentIndex()); -// lineEdit()->setPalette(QApplication::palette()); + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Text,Qt::red); - if (text.isEmpty()) - return; + int index = findText(text); - if (text == previous) - return; - - qDebug() << "textChanged"; - if (findText(text) != -1) { - QPalette *palette = new QPalette(); - palette->setColor(QPalette::Text,Qt::red); + if (text.isEmpty() || (index != -1 && index != currentIndex())) { lineEdit()->setPalette(*palette); + } else { + lineEdit()->setPalette(QApplication::palette()); } } void ProfilesComboBox::slotEditingFinished() { - qDebug() << "returnpressed"; QString current = currentText(); QString previous = itemText(currentIndex()); + qDebug() << current << previous; + if (current.isEmpty()) return; @@ -82,9 +78,9 @@ void ProfilesComboBox::slotEditingFinished() if (findText(current) != -1) return; - if (currentIndex() == -1) { - addItem(currentText()); + addItem(current); + setCurrentIndex(findText(current)); } else { setItemText(currentIndex(), current); emit(profileRenamed(previous, current)); From a729b1b12a6502e7382c8a2bb3f79ed1e808bce1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 18:34:51 -0800 Subject: [PATCH 0329/1483] Snap to the ground after moving Depends on two factors: * End up close enough above to a walkable plane (it's within sMaxStep units down and is angled sMaxSlope or less) * Started out on the ground without any upward movement This also reduces the distance needed to be to the ground to 4 (from 10), and ensures the actor is 2 units above the ground when on it. Downward force is also removed when starting on the ground. --- apps/openmw/mwworld/physicssystem.cpp | 31 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a5dd7f3693..7a343604c0 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -102,6 +102,7 @@ namespace MWWorld } traceResults trace; //no initialization needed + bool onground = false; float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); @@ -117,22 +118,24 @@ namespace MWWorld } else { + if(!(movement.z > 0.0f)) + { + newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) + onground = true; + } + velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * movement / time; - velocity.z = physicActor->getVerticalForce(); + velocity.z += physicActor->getVerticalForce(); } - // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(velocity); - - if(gravity) + if(onground) { - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); - } + // if we're on the ground, force velocity to track it + clippedVelocity.z = velocity.z = std::max(0.0f, velocity.z); + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } Ogre::Vector3 lastNormal(0.0f); @@ -176,6 +179,14 @@ namespace MWWorld iterations++; } while(iterations < sMaxIterations && remainingTime > 0.0f); + if(onground) + { + newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) + newPosition.z = trace.endpos.z + 2.0f; + else + onground = false; + } physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; From 15dc82f4545d78318ec7d3655df22fd569615800 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 18:59:05 -0800 Subject: [PATCH 0330/1483] Increase step size to 15 --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7a343604c0..447c1fa2ab 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -26,7 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; - static const float sStepSize = 9.0f; + static const float sStepSize = 15.0f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 50; From 18b606fddff13307d1b9700e548de5dddb0e550a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 20:10:04 -0800 Subject: [PATCH 0331/1483] Use the PhysicActor's set/getOnGround method --- apps/openmw/mwworld/physicssystem.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 447c1fa2ab..4236665631 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -187,6 +187,7 @@ namespace MWWorld else onground = false; } + physicActor->setOnGround(onground); physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2b42e6f06d..77e29f9bef 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1418,17 +1418,13 @@ namespace MWWorld RefData &refdata = mPlayer->getPlayer().getRefData(); Ogre::Vector3 playerPos(refdata.getPosition().pos); - std::pair hit = mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); - bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); - - if(!isOnGround || isUnderwater(*currentCell->mCell, playerPos)) + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + if(!physactor->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) return 2; - if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; return 0; - } MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) From ac717373b1a47618a0392cd33da7c1bd836fc630 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 22:35:15 -0800 Subject: [PATCH 0332/1483] Add a method to check if an object is on the ground --- apps/openmw/mwbase/world.hpp | 5 +++-- apps/openmw/mwworld/worldimp.cpp | 11 +++++++++-- apps/openmw/mwworld/worldimp.hpp | 5 +++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3b71d421c8..278c0d0a95 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -286,8 +286,9 @@ namespace MWBase virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; - virtual bool isSwimming(const MWWorld::Ptr &object) = 0; - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) = 0; + virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; + virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const = 0; + virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual void togglePOV() = 0; virtual void togglePreviewMode(bool enable) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 77e29f9bef..f2d2e2c008 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1379,7 +1379,7 @@ namespace MWWorld } bool - World::isSwimming(const MWWorld::Ptr &object) + World::isSwimming(const MWWorld::Ptr &object) const { /// \todo add check ifActor() - only actors can swim float *fpos = object.getRefData().getPosition().pos; @@ -1393,7 +1393,7 @@ namespace MWWorld } bool - World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) + World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const { if (!(cell.mData.mFlags & ESM::Cell::HasWater)) { return false; @@ -1401,6 +1401,13 @@ namespace MWWorld return pos.z < cell.mWater; } + bool World::isOnGround(const MWWorld::Ptr &ptr) const + { + RefData &refdata = ptr.getRefData(); + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + return physactor && physactor->getOnGround(); + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d7b20ba176..39c87fce75 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -314,8 +314,9 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); - virtual bool isSwimming(const MWWorld::Ptr &object); - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos); + virtual bool isSwimming(const MWWorld::Ptr &object) const; + virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const; + virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { mRendering->togglePOV(); From 3348e8a436081c4ebbfbe39fd8296056be3c75d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 22:41:14 -0800 Subject: [PATCH 0333/1483] Clarify a comment --- apps/openmw/mwmechanics/character.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d67964b846..eb39070410 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,7 +45,7 @@ enum CharacterState { CharState_SwimRunLeft, CharState_SwimRunRight, - /* Must be last! */ + /* Death states must be last! */ CharState_Death1, CharState_Death2, CharState_Death3, From e1a1530774bdb21bd2314b9bd2e48947cf198933 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 01:27:57 -0800 Subject: [PATCH 0334/1483] Better implement Npc::getSpeed --- apps/openmw/mwclass/npc.cpp | 84 +++++++++++++++++++++++++++++++++++-- apps/openmw/mwclass/npc.hpp | 17 ++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3666d9d6ba..d135d26838 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -55,9 +55,30 @@ namespace MWClass { void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const { + static bool inited = false; + if(!inited) + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + fMinWalkSpeed = gmst.find("fMinWalkSpeed"); + fMaxWalkSpeed = gmst.find("fMaxWalkSpeed"); + fEncumberedMoveEffect = gmst.find("fEncumberedMoveEffect"); + fSneakSpeedMultiplier = gmst.find("fSneakSpeedMultiplier"); + fAthleticsRunBonus = gmst.find("fAthleticsRunBonus"); + fBaseRunMultiplier = gmst.find("fBaseRunMultiplier"); + fMinFlySpeed = gmst.find("fMinFlySpeed"); + fMaxFlySpeed = gmst.find("fMaxFlySpeed"); + fSwimRunBase = gmst.find("fSwimRunBase"); + fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult"); + // Added in Tribunal/Bloodmoon, may not exist + fWereWolfRunMult = gmst.search("fWereWolfRunMult"); + + inited = true; + } if (!ptr.getRefData().getCustomData()) { - std::auto_ptr data (new CustomData); + std::auto_ptr data(new CustomData); MWWorld::LiveCellRef *ref = ptr.get(); @@ -297,9 +318,54 @@ namespace MWClass return false; } - float Npc::getSpeed (const MWWorld::Ptr& ptr) const + float Npc::getSpeed(const MWWorld::Ptr& ptr) const { - return getStance (ptr, Run) ? 600 : 300; // TODO calculate these values from stats + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr); + + float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified()* + (fMaxWalkSpeed->getFloat() - fMinWalkSpeed->getFloat()); + walkSpeed *= 1.0f - fEncumberedMoveEffect->getFloat()*normalizedEncumbrance; + walkSpeed = std::max(0.0f, walkSpeed); + if(Npc::getStance(ptr, Sneak, false)) + walkSpeed *= fSneakSpeedMultiplier->getFloat(); + float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * + fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); + + float moveSpeed; + if(normalizedEncumbrance > 1.0f) + moveSpeed = 0.0f; + else if(0/*world->isFlying(ptr)*/) + { + float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + + 0.0f/*levitationBonus*/); + flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); + flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; + flySpeed = std::max(0.0f, flySpeed); + moveSpeed = flySpeed; + } + else if(world->isSwimming(ptr)) + { + float swimSpeed = walkSpeed; + if(Npc::getStance(ptr, Run, false)) + swimSpeed = runSpeed; + swimSpeed *= 1.0f + 0.01f * 0.0f/*swiftSwimBonus*/; + swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* + fSwimRunAthleticsMult->getFloat(); + moveSpeed = swimSpeed; + } + else if(Npc::getStance(ptr, Run, false)) + moveSpeed = runSpeed; + else + moveSpeed = walkSpeed; + + if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) + moveSpeed *= 0.75f; + if(npcdata->mNpcStats.isWerewolf() && Npc::getStance(ptr, Run, false)) + moveSpeed *= fWereWolfRunMult->getFloat(); + + return moveSpeed; } MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const @@ -416,4 +482,16 @@ namespace MWClass return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell); } + + const ESM::GameSetting *Npc::fMinWalkSpeed; + const ESM::GameSetting *Npc::fMaxWalkSpeed; + const ESM::GameSetting *Npc::fEncumberedMoveEffect; + const ESM::GameSetting *Npc::fSneakSpeedMultiplier; + const ESM::GameSetting *Npc::fAthleticsRunBonus; + const ESM::GameSetting *Npc::fBaseRunMultiplier; + const ESM::GameSetting *Npc::fMinFlySpeed; + const ESM::GameSetting *Npc::fMaxFlySpeed; + const ESM::GameSetting *Npc::fSwimRunBase; + const ESM::GameSetting *Npc::fSwimRunAthleticsMult; + const ESM::GameSetting *Npc::fWereWolfRunMult; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 20c2da4b14..a97e4c42ee 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -3,6 +3,11 @@ #include "../mwworld/class.hpp" +namespace ESM +{ + class GameSetting; +} + namespace MWClass { class Npc : public MWWorld::Class @@ -12,6 +17,18 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + static const ESM::GameSetting *fMinWalkSpeed; + static const ESM::GameSetting *fMaxWalkSpeed; + static const ESM::GameSetting *fEncumberedMoveEffect; + static const ESM::GameSetting *fSneakSpeedMultiplier; + static const ESM::GameSetting *fAthleticsRunBonus; + static const ESM::GameSetting *fBaseRunMultiplier; + static const ESM::GameSetting *fMinFlySpeed; + static const ESM::GameSetting *fMaxFlySpeed; + static const ESM::GameSetting *fSwimRunBase; + static const ESM::GameSetting *fSwimRunAthleticsMult; + static const ESM::GameSetting *fWereWolfRunMult; + public: virtual std::string getId (const MWWorld::Ptr& ptr) const; From ff0099fa6e89c97f5f269d2f25adc66a5540edfc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 02:15:39 -0800 Subject: [PATCH 0335/1483] Scale the animation speed based on the animation velocity and movement speed This may not be totoally correct since it takes the whole animation into account, rather than just the looping portion. But it's good enough for now. --- apps/openmw/mwmechanics/character.cpp | 5 ++-- apps/openmw/mwrender/animation.cpp | 33 +++++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 4 ++-- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b6e96bdf5e..c40fac40aa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,6 +172,7 @@ Ogre::Vector3 CharacterController::update(float duration) { const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + const float speed = cls.getSpeed(mPtr); bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); @@ -204,9 +205,7 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) { - // FIXME: The speed should actually be determined by the character's - // stance (running, sneaking, etc) and stats - mAnimation->setSpeedMult(1.0f); + mAnimation->setSpeed(speed); movement += mAnimation->runAnimation(duration); } mSkipAnim = false; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9d9631ecea..1a606992a2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -28,6 +28,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentTime(0.0f) , mPlaying(false) , mLooping(false) + , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { } @@ -161,6 +162,13 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) mAccumulate = accum; } +void Animation::setSpeed(float speed) +{ + mAnimSpeedMult = 1.0f; + if(mAnimVelocity > 1.0f && speed > 0.0f) + mAnimSpeedMult = speed / mAnimVelocity; +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { @@ -255,6 +263,31 @@ void Animation::play(const std::string &groupname, const std::string &start, boo { mCurrentAnim = (*iter)->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mAnimVelocity = 0.0f; + + if(mNonAccumRoot) + { + const Ogre::NodeAnimationTrack *track = 0; + + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track && track->getNumKeyFrames() > 1) + { + const Ogre::TransformKeyFrame *startkf, *endkf; + startkf = static_cast(track->getKeyFrame(0)); + endkf = static_cast(track->getKeyFrame(track->getNumKeyFrames() - 1)); + + mAnimVelocity = startkf->getTranslate().distance(endkf->getTranslate()) / + mCurrentAnim->getLength(); + } + } + found = true; break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ee73193bf5..fc35c06be6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -36,6 +36,7 @@ protected: bool mPlaying; bool mLooping; + float mAnimVelocity; float mAnimSpeedMult; /* Applies the given animation to the given skeleton instance, using the specified time. */ @@ -73,8 +74,7 @@ public: // should be on the scale of 0 to 1. void setAccumulation(const Ogre::Vector3 &accum); - void setSpeedMult(float speedmult) - { mAnimSpeedMult = speedmult; } + void setSpeed(float speed); void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); From e4341525c859a94250de4c09165737cdd81b64e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 04:45:28 -0800 Subject: [PATCH 0336/1483] Add a jump state Currently unused --- apps/openmw/mwmechanics/character.cpp | 5 ++++- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c40fac40aa..376092256b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -68,6 +68,8 @@ static const struct { { CharState_SwimRunLeft, "swimrunleft" }, { CharState_SwimRunRight, "swimrunright" }, + { CharState_Jump, "jump" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -170,11 +172,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); const float speed = cls.getSpeed(mPtr); - bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); if(std::abs(vec.x/2.0f) > std::abs(vec.y)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index eb39070410..996687a3e1 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,6 +45,8 @@ enum CharacterState { CharState_SwimRunLeft, CharState_SwimRunRight, + CharState_Jump, + /* Death states must be last! */ CharState_Death1, CharState_Death2, From c57001e3bdda8a0b60eef303a49c4cf3eddd5f70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 05:11:06 -0800 Subject: [PATCH 0337/1483] Remove an unused field --- apps/openmw/mwworld/physicssystem.cpp | 4 +--- apps/openmw/mwworld/physicssystem.hpp | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 4236665631..240f1c435b 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -196,7 +196,7 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : - mRender(_rend), mEngine(0), mFreeFly (true) + mRender(_rend), mEngine(0) { // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); @@ -460,12 +460,10 @@ namespace MWWorld if(cmode) { act->enableCollisions(false); - mFreeFly = true; return false; } else { - mFreeFly = false; act->enableCollisions(true); return true; } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index cbdd9935eb..60c8246ae3 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -85,7 +85,6 @@ namespace MWWorld OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; - bool mFreeFly; std::map handleToMesh; PhysicsSystem (const PhysicsSystem&); From 990895fd2b9aab702c79a8e48fba2b6b6e3cf1c3 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Fri, 15 Feb 2013 14:12:25 +0100 Subject: [PATCH 0338/1483] Mainwindow size and position now gets saved/restored --- apps/launcher/maindialog.cpp | 14 ++++++++++++++ apps/launcher/utils/profilescombobox.cpp | 12 +++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index f48ea603bf..7b453671c7 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -169,6 +169,7 @@ bool MainDialog::setup() return false; } + loadSettings(); return true; } @@ -182,7 +183,14 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) void MainDialog::loadSettings() { + int width = mLauncherSettings.value(QString("General/MainWindow/width")).toInt(); + int height = mLauncherSettings.value(QString("General/MainWindow/height")).toInt(); + int posX = mLauncherSettings.value(QString("General/MainWindow/posx")).toInt(); + int posY = mLauncherSettings.value(QString("General/MainWindow/posy")).toInt(); + + resize(width, height); + move(posX, posY); } void MainDialog::saveSettings() @@ -193,6 +201,12 @@ void MainDialog::saveSettings() mLauncherSettings.setValue(QString("General/MainWindow/width"), width); mLauncherSettings.setValue(QString("General/MainWindow/height"), height); + QString posX = QString::number(this->pos().x()); + QString posY = QString::number(this->pos().y()); + + mLauncherSettings.setValue(QString("General/MainWindow/posx"), posX); + mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY); + qDebug() << "size: " << width << height; } diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp index a2c8668cb5..4c258dae60 100644 --- a/apps/launcher/utils/profilescombobox.cpp +++ b/apps/launcher/utils/profilescombobox.cpp @@ -69,6 +69,9 @@ void ProfilesComboBox::slotEditingFinished() qDebug() << current << previous; + if (currentIndex() == -1) + return; + if (current.isEmpty()) return; @@ -78,13 +81,8 @@ void ProfilesComboBox::slotEditingFinished() if (findText(current) != -1) return; - if (currentIndex() == -1) { - addItem(current); - setCurrentIndex(findText(current)); - } else { - setItemText(currentIndex(), current); - emit(profileRenamed(previous, current)); - } + setItemText(currentIndex(), current); + emit(profileRenamed(previous, current)); } void ProfilesComboBox::slotIndexChanged(int index) From 43e9ad87331d073d69c5d571acad50020263f849 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Fri, 15 Feb 2013 14:26:09 +0100 Subject: [PATCH 0339/1483] The text color of the profiles dialog now turns red on invalid names --- apps/launcher/utils/textinputdialog.cpp | 46 ++++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/launcher/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp index 16cadb6619..ec72e54328 100644 --- a/apps/launcher/utils/textinputdialog.cpp +++ b/apps/launcher/utils/textinputdialog.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -17,9 +18,19 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid mButtonBox->addButton(QDialogButtonBox::Ok); mButtonBox->addButton(QDialogButtonBox::Cancel); - setMaximumHeight(height()); - setOkButtonEnabled(false); - setModal(true); + // Line edit + QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore + mLineEdit = new LineEdit(this); + mLineEdit->setValidator(validator); + mLineEdit->setCompleter(0); + + QLabel *label = new QLabel(this); + label->setText(text); + + QVBoxLayout *dialogLayout = new QVBoxLayout(this); + dialogLayout->addWidget(label); + dialogLayout->addWidget(mLineEdit); + dialogLayout->addWidget(mButtonBox); // Messageboxes on mac have no title #ifndef Q_OS_MAC @@ -28,22 +39,13 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid Q_UNUSED(title); #endif - QLabel *label = new QLabel(this); - label->setText(text); - - // Line edit - QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore - mLineEdit = new LineEdit(this); - mLineEdit->setValidator(validator); - mLineEdit->setCompleter(0); - - QVBoxLayout *dialogLayout = new QVBoxLayout(this); - dialogLayout->addWidget(label); - dialogLayout->addWidget(mLineEdit); - dialogLayout->addWidget(mButtonBox); + setMaximumHeight(height()); + setOkButtonEnabled(false); + setModal(true); connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); + } int TextInputDialog::exec() @@ -55,7 +57,17 @@ int TextInputDialog::exec() void TextInputDialog::setOkButtonEnabled(bool enabled) { - QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok); okButton->setEnabled(enabled); + + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Text,Qt::red); + + if (enabled) { + mLineEdit->setPalette(QApplication::palette()); + } else { + // Existing profile name, make the text red + mLineEdit->setPalette(*palette); + } + } From 4da11a96a5d51c0c22b62e033fb46ffaa7823f6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 Feb 2013 17:34:55 +0100 Subject: [PATCH 0340/1483] Fixed gold ref count always becoming 1 when dropped on the ground --- apps/openmw/mwclass/misc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 94d40bcb7c..a21cc2aef6 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -210,6 +210,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell); + newPtr.getRefData ().setCount(goldAmount); } else { MWWorld::LiveCellRef *ref = ptr.get(); From df5919f2c59eeca4d38dd60b888d2aff019548b9 Mon Sep 17 00:00:00 2001 From: Douglas Mencken Date: Sat, 2 Feb 2013 10:17:20 -0500 Subject: [PATCH 0341/1483] Use `signed char' explicitly where needed. It is important because: - It is implementation-dependent if plain `char' signed or not. - C standard defines three *distinct* types: char, signed char, and unsigned char. - Assuming that char is always unsigned or signed can lead to compile-time and run-time errors. You can also use int8_t, but then it would be less obvious for developers to never assume that char is always unsigned (or always signed). Conflicts: components/esm/loadcell.hpp --- apps/esmtool/labels.cpp | 16 ++++++++-------- apps/esmtool/labels.hpp | 6 +++--- components/esm/loadcell.hpp | 12 ++++++------ components/esm/loaddial.hpp | 2 +- components/to_utf8/tables_gen.hpp | 6 +++--- components/to_utf8/to_utf8.cpp | 2 +- components/to_utf8/to_utf8.hpp | 2 +- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 9fb2332379..d7d3cf9ce6 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -16,7 +16,7 @@ #include #include -std::string bodyPartLabel(char idx) +std::string bodyPartLabel(signed char idx) { const char *bodyPartLabels[] = { "Head", @@ -47,14 +47,14 @@ std::string bodyPartLabel(char idx) "Weapon", "Tail" }; - + if ((int)idx >= 0 && (int)(idx) <= 26) return bodyPartLabels[(int)(idx)]; else return "Invalid"; } -std::string meshPartLabel(char idx) +std::string meshPartLabel(signed char idx) { const char *meshPartLabels[] = { "Head", @@ -73,25 +73,25 @@ std::string meshPartLabel(char idx) "Clavicle", "Tail" }; - + if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MP_Tail) return meshPartLabels[(int)(idx)]; else return "Invalid"; } -std::string meshTypeLabel(char idx) +std::string meshTypeLabel(signed char idx) { const char *meshTypeLabels[] = { "Skin", "Clothing", "Armor" }; - + if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MT_Armor) return meshTypeLabels[(int)(idx)]; else - return "Invalid"; + return "Invalid"; } std::string clothingTypeLabel(int idx) @@ -108,7 +108,7 @@ std::string clothingTypeLabel(int idx) "Ring", "Amulet" }; - + if (idx >= 0 && idx <= 9) return clothingTypeLabels[idx]; else diff --git a/apps/esmtool/labels.hpp b/apps/esmtool/labels.hpp index 7f1ff79865..bf39580374 100644 --- a/apps/esmtool/labels.hpp +++ b/apps/esmtool/labels.hpp @@ -3,9 +3,9 @@ #include -std::string bodyPartLabel(char idx); -std::string meshPartLabel(char idx); -std::string meshTypeLabel(char idx); +std::string bodyPartLabel(signed char idx); +std::string meshPartLabel(signed char idx); +std::string meshTypeLabel(signed char idx); std::string clothingTypeLabel(int idx); std::string armorTypeLabel(int idx); std::string dialogTypeLabel(int idx); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 27bdd77ce1..de467666ee 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -77,8 +77,8 @@ public: std::string mKey, mTrap; // Key and trap ID names, if any // No idea - occurs ONCE in Morrowind.esm, for an activator - char mUnam; - + signed char mUnam; + // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. int mDeleted; @@ -164,14 +164,14 @@ struct Cell bool mWaterInt; int mMapColor; int mNAM0; - + // References "leased" from another cell (i.e. a different cell // introduced this ref, and it has been moved here by a plugin) CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; - + void load(ESMReader &esm, MWWorld::ESMStore &store); - + // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. void load(ESMReader &esm) {}; @@ -209,7 +209,7 @@ struct Cell reuse one memory location without blanking it between calls. */ static bool getNextRef(ESMReader &esm, CellRef &ref); - + /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. */ diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 078c788119..61f3f763de 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -30,7 +30,7 @@ struct Dialogue }; std::string mId; - char mType; + signed char mType; std::vector mInfo; void load(ESMReader &esm); diff --git a/components/to_utf8/tables_gen.hpp b/components/to_utf8/tables_gen.hpp index 9c32f0427d..a1d4b6d80d 100644 --- a/components/to_utf8/tables_gen.hpp +++ b/components/to_utf8/tables_gen.hpp @@ -8,7 +8,7 @@ namespace ToUTF8 /// Central European and Eastern European languages that use Latin script, /// such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, /// Serbian (Latin script), Romanian and Albanian. -static char windows_1250[] = +static signed char windows_1250[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, @@ -270,7 +270,7 @@ static char windows_1250[] = /// Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic /// and other languages -static char windows_1251[] = +static signed char windows_1251[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, @@ -531,7 +531,7 @@ static char windows_1251[] = }; /// Latin alphabet used by English and some other Western languages -static char windows_1252[] = +static signed char windows_1252[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 275f5483f3..e2a1b1220f 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -216,7 +216,7 @@ void Utf8Encoder::copyFromArray(unsigned char ch, char* &out) return; } - const char *in = translationArray + ch*6; + const signed char *in = translationArray + ch*6; int len = *(in++); for (int i=0; i mOutput; - char* translationArray; + signed char* translationArray; }; } From c965bd8e181b0bf9a81df51b11770e97f49711ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 17:22:55 -0800 Subject: [PATCH 0342/1483] Increase step size to 30 --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 240f1c435b..058160595d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -26,7 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; - static const float sStepSize = 15.0f; + static const float sStepSize = 30.0f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 50; From 158e18b98d879b4ba9d87c8a1bc6d72d5320db65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Feb 2013 00:30:07 -0800 Subject: [PATCH 0343/1483] Remove an unused method --- apps/openmw/mwbase/world.hpp | 3 --- apps/openmw/mwworld/worldimp.hpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 278c0d0a95..da670cf23e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -307,9 +307,6 @@ namespace MWBase /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) - /// \todo Probably shouldn't be here - virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const = 0; - /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 39c87fce75..8b9b39617b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -349,10 +349,6 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) - /// \todo Probably shouldn't be here - virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const - { return mPhysEngine; } - /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); From a3e421167b3703e9943d82fb804073c99ac55651 Mon Sep 17 00:00:00 2001 From: Douglas Mencken Date: Sat, 9 Feb 2013 15:11:09 -0500 Subject: [PATCH 0344/1483] esmtool/labels: bodyPartLabel, meshPartLabel, meshTypeLabel Signed chars, unsigned chars... Just use int for index everywhere. --- apps/esmtool/labels.cpp | 18 +++++++++--------- apps/esmtool/labels.hpp | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index d7d3cf9ce6..f08c31003c 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -16,7 +16,7 @@ #include #include -std::string bodyPartLabel(signed char idx) +std::string bodyPartLabel(int idx) { const char *bodyPartLabels[] = { "Head", @@ -48,13 +48,13 @@ std::string bodyPartLabel(signed char idx) "Tail" }; - if ((int)idx >= 0 && (int)(idx) <= 26) - return bodyPartLabels[(int)(idx)]; + if (idx >= 0 && idx <= 26) + return bodyPartLabels[idx]; else return "Invalid"; } -std::string meshPartLabel(signed char idx) +std::string meshPartLabel(int idx) { const char *meshPartLabels[] = { "Head", @@ -74,13 +74,13 @@ std::string meshPartLabel(signed char idx) "Tail" }; - if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MP_Tail) - return meshPartLabels[(int)(idx)]; + if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail) + return meshPartLabels[idx]; else return "Invalid"; } -std::string meshTypeLabel(signed char idx) +std::string meshTypeLabel(int idx) { const char *meshTypeLabels[] = { "Skin", @@ -88,8 +88,8 @@ std::string meshTypeLabel(signed char idx) "Armor" }; - if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MT_Armor) - return meshTypeLabels[(int)(idx)]; + if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor) + return meshTypeLabels[idx]; else return "Invalid"; } diff --git a/apps/esmtool/labels.hpp b/apps/esmtool/labels.hpp index bf39580374..48d7b249bd 100644 --- a/apps/esmtool/labels.hpp +++ b/apps/esmtool/labels.hpp @@ -3,9 +3,9 @@ #include -std::string bodyPartLabel(signed char idx); -std::string meshPartLabel(signed char idx); -std::string meshTypeLabel(signed char idx); +std::string bodyPartLabel(int idx); +std::string meshPartLabel(int idx); +std::string meshTypeLabel(int idx); std::string clothingTypeLabel(int idx); std::string armorTypeLabel(int idx); std::string dialogTypeLabel(int idx); From eb09662f1ddd67cdae0c5af2b1d96aa0ceba3d9e Mon Sep 17 00:00:00 2001 From: Douglas Mencken Date: Thu, 14 Feb 2013 04:22:00 -0500 Subject: [PATCH 0345/1483] Don't include boost/filesystem/v3/operations.hpp, use boost/filesystem/operations.hpp instead. It is boost headers' job to deal with their internals. --- apps/openmw/mwworld/esmstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 1666ad823a..257676076c 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace MWWorld { From 7d918caa9355f59cb37f38c326a5fbf9523d9604 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Feb 2013 16:26:40 +0100 Subject: [PATCH 0346/1483] Don't allow dialogue if player controls are disabled. --- apps/openmw/mwworld/actiontalk.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 905497f85b..59b37370a2 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -3,6 +3,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/inputmanager.hpp" namespace MWWorld { @@ -10,6 +11,7 @@ namespace MWWorld void ActionTalk::executeImp (const Ptr& actor) { - MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + if (MWBase::Environment::get().getInputManager ()->getControlSwitch ("playercontrols")) + MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); } } From 0bc34c1c0d7eb10fd7eb942efd23d7443be6e328 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Feb 2013 16:40:44 +0100 Subject: [PATCH 0347/1483] Action::executeImp returns a bool value to indicate if the sound should be played. --- apps/openmw/mwworld/action.cpp | 4 +--- apps/openmw/mwworld/action.hpp | 3 ++- apps/openmw/mwworld/actionalchemy.cpp | 3 ++- apps/openmw/mwworld/actionalchemy.hpp | 2 +- apps/openmw/mwworld/actionapply.cpp | 6 ++++-- apps/openmw/mwworld/actionapply.hpp | 4 ++-- apps/openmw/mwworld/actioneat.cpp | 4 +++- apps/openmw/mwworld/actioneat.hpp | 2 +- apps/openmw/mwworld/actionequip.cpp | 4 +++- apps/openmw/mwworld/actionequip.hpp | 2 +- apps/openmw/mwworld/actionopen.cpp | 5 +++-- apps/openmw/mwworld/actionopen.hpp | 2 +- apps/openmw/mwworld/actionread.cpp | 3 ++- apps/openmw/mwworld/actionread.hpp | 2 +- apps/openmw/mwworld/actiontake.cpp | 6 ++++-- apps/openmw/mwworld/actiontake.hpp | 2 +- apps/openmw/mwworld/actiontalk.cpp | 6 +++++- apps/openmw/mwworld/actiontalk.hpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 3 ++- apps/openmw/mwworld/actionteleport.hpp | 2 +- apps/openmw/mwworld/failedaction.cpp | 9 +++++---- apps/openmw/mwworld/failedaction.hpp | 4 ++-- apps/openmw/mwworld/nullaction.hpp | 2 +- 23 files changed, 49 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index a5199fb3ea..b4897109a8 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -18,7 +18,7 @@ MWWorld::Action::~Action() {} void MWWorld::Action::execute (const Ptr& actor) { - if (!mSoundId.empty()) + if (!mSoundId.empty() && executeImp (actor)) { if (mKeepSound && actor.getRefData().getHandle()=="player") { @@ -35,8 +35,6 @@ void MWWorld::Action::execute (const Ptr& actor) mKeepSound ? MWBase::SoundManager::Play_NoTrack : MWBase::SoundManager::Play_Normal); } } - - executeImp (actor); } void MWWorld::Action::setSound (const std::string& id) diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index d8e5d93bb2..42c2ad0844 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -18,7 +18,8 @@ namespace MWWorld Action (const Action& action); Action& operator= (const Action& action); - virtual void executeImp (const Ptr& actor) = 0; + /// @return true if the sound should be played, false if not (e.g. if the action is not allowed) + virtual bool executeImp (const Ptr& actor) = 0; protected: diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index bba75bc499..20093279e0 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -5,8 +5,9 @@ namespace MWWorld { - void ActionAlchemy::executeImp (const Ptr& actor) + bool ActionAlchemy::executeImp (const Ptr& actor) { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy); + return true; } } diff --git a/apps/openmw/mwworld/actionalchemy.hpp b/apps/openmw/mwworld/actionalchemy.hpp index e6d1a7976c..814f347c88 100644 --- a/apps/openmw/mwworld/actionalchemy.hpp +++ b/apps/openmw/mwworld/actionalchemy.hpp @@ -7,7 +7,7 @@ namespace MWWorld { class ActionAlchemy : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); }; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index f78b8f7988..2a41b5613f 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -9,9 +9,10 @@ namespace MWWorld : Action (false, target), mId (id) {} - void ActionApply::executeImp (const Ptr& actor) + bool ActionApply::executeImp (const Ptr& actor) { MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor); + return true; } @@ -20,9 +21,10 @@ namespace MWWorld : Action (false, target), mId (id), mSkillIndex (skillIndex), mUsageType (usageType) {} - void ActionApplyWithSkill::executeImp (const Ptr& actor) + bool ActionApplyWithSkill::executeImp (const Ptr& actor) { if (MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor) && mUsageType!=-1) MWWorld::Class::get (getTarget()).skillUsageSucceeded (actor, mSkillIndex, mUsageType); + return true; } } diff --git a/apps/openmw/mwworld/actionapply.hpp b/apps/openmw/mwworld/actionapply.hpp index 3353ae0eed..53b2de1d08 100644 --- a/apps/openmw/mwworld/actionapply.hpp +++ b/apps/openmw/mwworld/actionapply.hpp @@ -13,7 +13,7 @@ namespace MWWorld { std::string mId; - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: @@ -26,7 +26,7 @@ namespace MWWorld int mSkillIndex; int mUsageType; - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 63efff738e..81c45f051e 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -16,7 +16,7 @@ namespace MWWorld { - void ActionEat::executeImp (const Ptr& actor) + bool ActionEat::executeImp (const Ptr& actor) { // remove used item getTarget().getRefData().setCount (getTarget().getRefData().getCount()-1); @@ -42,6 +42,8 @@ namespace MWWorld // increase skill Class::get (actor).skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } + + return true; } ActionEat::ActionEat (const MWWorld::Ptr& object) : Action (false, object) {} diff --git a/apps/openmw/mwworld/actioneat.hpp b/apps/openmw/mwworld/actioneat.hpp index ce5330db77..265f5aa68a 100644 --- a/apps/openmw/mwworld/actioneat.hpp +++ b/apps/openmw/mwworld/actioneat.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionEat : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 2d257aa614..902e0fdb69 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -16,7 +16,7 @@ namespace MWWorld { } - void ActionEquip::executeImp (const Ptr& actor) + bool ActionEquip::executeImp (const Ptr& actor) { MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); @@ -113,5 +113,7 @@ namespace MWWorld /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); + + return true; } } diff --git a/apps/openmw/mwworld/actionequip.hpp b/apps/openmw/mwworld/actionequip.hpp index 3b56c74027..fb3a1ac10e 100644 --- a/apps/openmw/mwworld/actionequip.hpp +++ b/apps/openmw/mwworld/actionequip.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionEquip : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: /// @param item to equip diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 040a3856e8..da570dff02 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -14,12 +14,13 @@ namespace MWWorld { } - void ActionOpen::executeImp (const MWWorld::Ptr& actor) + bool ActionOpen::executeImp (const MWWorld::Ptr& actor) { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return; + return false; MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget()); + return true; } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index c49ebefa51..42ad4aecbe 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -10,7 +10,7 @@ namespace MWWorld { class ActionOpen : public Action { - virtual void executeImp (const MWWorld::Ptr& actor); + virtual bool executeImp (const MWWorld::Ptr& actor); public: ActionOpen (const Ptr& container); diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 6d5d9d8fde..157b051d6f 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -19,7 +19,7 @@ namespace MWWorld { } - void ActionRead::executeImp (const MWWorld::Ptr& actor) + bool ActionRead::executeImp (const MWWorld::Ptr& actor) { LiveCellRef *ref = getTarget().get(); @@ -53,5 +53,6 @@ namespace MWWorld npcStats.flagAsUsed (ref->mBase->mId); } + return true; } } diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index 00a4756dda..dfb536c64a 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionRead : public Action { - virtual void executeImp (const MWWorld::Ptr& actor); + virtual bool executeImp (const MWWorld::Ptr& actor); public: /// @param book or scroll to read diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index fd28dd52eb..fef8a7e73a 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -12,10 +12,10 @@ namespace MWWorld { ActionTake::ActionTake (const MWWorld::Ptr& object) : Action (true, object) {} - void ActionTake::executeImp (const Ptr& actor) + bool ActionTake::executeImp (const Ptr& actor) { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return; + return false; // insert into player's inventory MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPtr ("player", true); @@ -23,5 +23,7 @@ namespace MWWorld MWWorld::Class::get (player).getContainerStore (player).add (getTarget()); MWBase::Environment::get().getWorld()->deleteObject (getTarget()); + + return true; } } diff --git a/apps/openmw/mwworld/actiontake.hpp b/apps/openmw/mwworld/actiontake.hpp index b0a9b82478..2a87156d0a 100644 --- a/apps/openmw/mwworld/actiontake.hpp +++ b/apps/openmw/mwworld/actiontake.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionTake : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 59b37370a2..36c54f00ee 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -9,9 +9,13 @@ namespace MWWorld { ActionTalk::ActionTalk (const Ptr& actor) : Action (false, actor) {} - void ActionTalk::executeImp (const Ptr& actor) + bool ActionTalk::executeImp (const Ptr& actor) { if (MWBase::Environment::get().getInputManager ()->getControlSwitch ("playercontrols")) + { MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + return true; + } + return false; } } diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp index b88b168d8c..91c71dc79b 100644 --- a/apps/openmw/mwworld/actiontalk.hpp +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionTalk : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index ae5ffc3b90..9b21cc8763 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -12,11 +12,12 @@ namespace MWWorld { } - void ActionTeleport::executeImp (const Ptr& actor) + bool ActionTeleport::executeImp (const Ptr& actor) { if (mCellName.empty()) MWBase::Environment::get().getWorld()->changeToExteriorCell (mPosition); else MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, mPosition); + return true; } } diff --git a/apps/openmw/mwworld/actionteleport.hpp b/apps/openmw/mwworld/actionteleport.hpp index a13cb61b21..4f771cac99 100644 --- a/apps/openmw/mwworld/actionteleport.hpp +++ b/apps/openmw/mwworld/actionteleport.hpp @@ -14,7 +14,7 @@ namespace MWWorld std::string mCellName; ESM::Position mPosition; - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index ec763dba01..7ce27f76f9 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -11,11 +11,12 @@ namespace MWWorld { } - void FailedAction::executeImp (const Ptr& actor) + bool FailedAction::executeImp (const Ptr& actor) { if ( actor.getRefData().getHandle()=="player" && !(message.empty())) - { - MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); - } + { + MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); + } + return false; } } diff --git a/apps/openmw/mwworld/failedaction.hpp b/apps/openmw/mwworld/failedaction.hpp index e736bfb63b..7d64afe74b 100644 --- a/apps/openmw/mwworld/failedaction.hpp +++ b/apps/openmw/mwworld/failedaction.hpp @@ -10,11 +10,11 @@ namespace MWWorld { std::string message; - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: FailedAction (const std::string& message = std::string()); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwworld/nullaction.hpp b/apps/openmw/mwworld/nullaction.hpp index 7ef8b4a065..f5544e4c10 100644 --- a/apps/openmw/mwworld/nullaction.hpp +++ b/apps/openmw/mwworld/nullaction.hpp @@ -8,7 +8,7 @@ namespace MWWorld /// \brief Action: do nothing class NullAction : public Action { - virtual void executeImp (const Ptr& actor) {} + virtual bool executeImp (const Ptr& actor) {return false;} }; } From a5c8d5748f990025ef7a3dd3eb5bb5d291fe9703 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Feb 2013 18:05:25 +0100 Subject: [PATCH 0348/1483] fix FailedAction. --- apps/openmw/mwworld/failedaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index 7ce27f76f9..e2ca78b2c7 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -17,6 +17,6 @@ namespace MWWorld { MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); } - return false; + return true; } } From f0220fb06b099dd48aa4c3825135fabecb9cd400 Mon Sep 17 00:00:00 2001 From: Wareya Date: Sat, 16 Feb 2013 13:35:03 -0500 Subject: [PATCH 0349/1483] Implement "Rest Until Healed" Fixes: https://bugs.openmw.org/issues/563 --- apps/openmw/mwgui/waitdialog.cpp | 62 ++++++++++++++++++++++++++++---- apps/openmw/mwgui/waitdialog.hpp | 3 +- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 4f2c98c080..2953ca58d3 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,5 +1,8 @@ #include "waitdialog.hpp" +#include +#include + #include #include @@ -14,6 +17,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" #include "widgets.hpp" @@ -132,21 +136,66 @@ namespace MWGui void WaitDialog::onUntilHealedButtonClicked(MyGUI::Widget* sender) { - startWaiting(); + // we need to sleep for a specific time, and since that isn't calculated yet, we'll do it here + // I'm making the assumption here that the # of hours rested is calculated when rest is started + // TODO: the rougher logic here (calculating the hourly deltas) should really go into helper funcs elsewhere + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::CreatureStats stats = MWWorld::Class::get(player).getCreatureStats(player); + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; + + bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(136)).mMagnitude > 0); + float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); + float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); + + // this massive duplication is why it has to be put into helper functions instead + float fFatigueReturnBase = store.get().find("fFatigueReturnBase")->getFloat(); + float fFatigueReturnMult = store.get().find("fFatigueReturnMult")->getFloat(); + float fEndFatigueMult = store.get().find("fEndFatigueMult")->getFloat(); + float capacity = MWWorld::Class::get(player).getCapacity(player); + float encumbrance = MWWorld::Class::get(player).getEncumbrance(player); + float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity); + if (normalizedEncumbrance > 1) + normalizedEncumbrance = 1; + float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); + hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified(); + + std::cout << "Calced health per hour: " << hourlyHealthDelta << std::endl; + + float healthHours = hourlyHealthDelta >= 0.0 + ? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta + : 1.0f; + std::cout << "Calced health hours: " << healthHours << std::endl; + std::cout << "getBase returns " << stats.getHealth().getBase() << ", getModified() returns " << stats.getHealth().getModified() << std::endl; + float magickaHours = stunted ? 0.0 : + hourlyMagickaDelta >= 0.0 + ? (stats.getMagicka().getBase() - stats.getMagicka().getCurrent()) / hourlyMagickaDelta + : 1.0f; + float fatigueHours = hourlyFatigueDelta >= 0.0 + ? (stats.getFatigue().getBase() - stats.getFatigue().getCurrent()) / hourlyFatigueDelta + : 1.0f; + + int autoHours = int(std::ceil( std::max(std::max(healthHours, magickaHours), std::max(fatigueHours, 1.0f)) )); // this should use a variadic max if possible + + startWaiting(autoHours); } void WaitDialog::onWaitButtonClicked(MyGUI::Widget* sender) { - startWaiting(); + startWaiting(mManualHours); } - void WaitDialog::startWaiting () + void WaitDialog::startWaiting(int hoursToWait) { MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2); setVisible(false); mProgressBar.setVisible (true); + mWaiting = true; mCurHour = 0; + mHours = hoursToWait; + mRemainingTime = 0.05; mProgressBar.setProgress (0, mHours); } @@ -159,7 +208,7 @@ namespace MWGui void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) { mHourText->setCaptionWithReplacing (boost::lexical_cast(position+1) + " #{sRestMenu2}"); - mHours = position+1; + mManualHours = position+1; } void WaitDialog::setCanRest (bool canRest) @@ -181,9 +230,9 @@ namespace MWGui mRemainingTime -= dt; - if (mRemainingTime < 0) + while (mRemainingTime < 0) { - mRemainingTime = 0.05; + mRemainingTime += 0.05; ++mCurHour; mProgressBar.setProgress (mCurHour, mHours); @@ -197,6 +246,7 @@ namespace MWGui if (mCurHour > mHours) stopWaiting(); + } void WaitDialog::stopWaiting () diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 6af565c6ed..c102d0fc67 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -47,6 +47,7 @@ namespace MWGui bool mSleeping; int mCurHour; int mHours; + int mManualHours; // stores the hours to rest selected via slider float mRemainingTime; WaitDialogProgressBar mProgressBar; @@ -58,7 +59,7 @@ namespace MWGui void setCanRest(bool canRest); - void startWaiting(); + void startWaiting(int hoursToWait); void stopWaiting(); }; From c98a81558151092542bc4882fb6a6ded4dcaddb0 Mon Sep 17 00:00:00 2001 From: Wareya Date: Sat, 16 Feb 2013 13:37:25 -0500 Subject: [PATCH 0350/1483] Remove debug printing from previous commit --- apps/openmw/mwgui/waitdialog.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 2953ca58d3..2c74dd2fd6 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,6 +1,5 @@ #include "waitdialog.hpp" -#include #include #include @@ -160,14 +159,10 @@ namespace MWGui normalizedEncumbrance = 1; float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified(); - - std::cout << "Calced health per hour: " << hourlyHealthDelta << std::endl; float healthHours = hourlyHealthDelta >= 0.0 ? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta - : 1.0f; - std::cout << "Calced health hours: " << healthHours << std::endl; - std::cout << "getBase returns " << stats.getHealth().getBase() << ", getModified() returns " << stats.getHealth().getModified() << std::endl; + : 1.0f; float magickaHours = stunted ? 0.0 : hourlyMagickaDelta >= 0.0 ? (stats.getMagicka().getBase() - stats.getMagicka().getCurrent()) / hourlyMagickaDelta From df8e502f8c5139a850fa74cc2ff53f3804fb970c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 02:52:49 +0100 Subject: [PATCH 0351/1483] Ouch, I used && instead of &, this broke actions without a sound --- apps/openmw/mwworld/action.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index b4897109a8..0d50d8deda 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -18,7 +18,7 @@ MWWorld::Action::~Action() {} void MWWorld::Action::execute (const Ptr& actor) { - if (!mSoundId.empty() && executeImp (actor)) + if (!mSoundId.empty() & executeImp (actor)) { if (mKeepSound && actor.getRefData().getHandle()=="player") { From 373de19aeec752958a37e9fe0f120ef95493ab1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 03:02:47 +0100 Subject: [PATCH 0352/1483] Removed dialogue fix again, now on separate branch --- apps/openmw/mwworld/actiontalk.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 36c54f00ee..6bee9eb26e 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -11,11 +11,7 @@ namespace MWWorld bool ActionTalk::executeImp (const Ptr& actor) { - if (MWBase::Environment::get().getInputManager ()->getControlSwitch ("playercontrols")) - { - MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); - return true; - } - return false; + MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + return true; } } From c4f17f5596efde3267c802f1463a0b822d97f70a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 03:03:41 +0100 Subject: [PATCH 0353/1483] playercontrols switch now disables activation in general (Chris' suggestion) --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 02a699eced..296ff3cc71 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -642,7 +642,8 @@ namespace MWInput void InputManager::activate() { - mEngine.activate(); + if (mControlSwitch["playercontrols"]) + mEngine.activate(); } void InputManager::toggleAutoMove() From ceefae81e8ea34fdafc2682b2f6a777d65b02587 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sun, 17 Feb 2013 07:46:50 -0600 Subject: [PATCH 0354/1483] fix for the opencs icon --- apps/opencs/CMakeLists.txt | 6 +++--- apps/opencs/main.cpp | 6 +++++- files/opencs/opencs.png | Bin 0 -> 65168 bytes files/opencs/resources.qrc | 5 +++++ 4 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 files/opencs/opencs.png create mode 100644 files/opencs/resources.qrc diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d1cfbea524..af8fb59817 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,7 +40,7 @@ opencs_units_noqt (model/tools opencs_units (view/doc - viewmanager view operations operation subview + viewmanager view operations operation subview startup ) opencs_units_noqt (view/doc @@ -73,7 +73,7 @@ opencs_units_noqt (view/tools set (OPENCS_US ) -set (OPENCS_RES +set (OPENCS_RES ../../files/opencs/resources.qrc ) source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) @@ -102,4 +102,4 @@ target_link_libraries(opencs ${Boost_LIBRARIES} ${QT_LIBRARIES} components -) \ No newline at end of file +) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 4b1a688c26..aa315804b2 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -5,6 +5,7 @@ #include #include +#include class Application : public QApplication { @@ -31,9 +32,12 @@ class Application : public QApplication int main(int argc, char *argv[]) { + Q_INIT_RESOURCE (resources); Application mApplication (argc, argv); + mApplication.setWindowIcon (QIcon (":./opencs.png")); + CS::Editor editor; return editor.run(); -} \ No newline at end of file +} diff --git a/files/opencs/opencs.png b/files/opencs/opencs.png new file mode 100644 index 0000000000000000000000000000000000000000..dddf220a3cbd0df1f4437ce4e00a95aef4b0e4a9 GIT binary patch literal 65168 zcmbq)^;a9+_caBILn%;Pin~(?PVodQDaEBgfkKMA1zOyT7bsA?xVsiDUYue<3c-U1 z4R4;$THn9m&05LK+~kM3bMM(_pS@3_-e{{46VMW1U|jBhK z!Ck>(B;c1A)z0^G>h1ygsMHXPN zmM!VaPgo+uIG+Zudar~A83$vJq;cRradEyFOsxC zbrY9Hf;C~_zoi_mUs9skw7>WC>Bi?9o*T;jd18n-={xuop1b#CrVCM(KHVjUcUW|3?C9s=kuN4E#WJJ{ zQRkjgwQl(3N|6IkvZ0-HpE907sC|$cq>T~hUZl?U{G)HJi5YwlTQ}>Q)Kgv)gm{7h znhT!Kvmue4$_JSLpn5H+8(7X0L^E)k?u=S9JK7*2Chj4XS2gt;P9w*%=$v;QkQ~UD zDbgj(gxJQv5uHiK$z%i8&a;HR)DmqF-sPKsiOS|zgb14z z@)d*LuTL6*IyggXW$PlJ&BpA`v<6%!pX{l05D!k~!t0e9; z$D1b`z_-t|tawVjvP%XL%Q&|3pkmh0;~^KLd(|scynN)oCGkkI;Q3QWf6;FNO2DqN zICF7J)0nAd%b$_TpCT->P`=S~ zc!-HyMZHVgX*>Ko)%Ol_8z}U(C{t|ix+~;_Eq}>Sy%8Cak=h+NTIn6p$3RCL%nZf; z9<-J*^BK|M5YTZ|&Pnfmv6LJSQ?AwfVJeWcx039Y!V*uuG-}o>fwL`~;{^ic50DdV^NuBvx-0T^7P|-bXS$uMQl4np^&k(10Q6u=YSl`jWcVwGZ36 zU<+exVj_7E|6IedZS||Upfa~gQXxi5Rr1iek!n(*INS|uvJc8XxYie}O^ zax-+O*=Z{)2-W;)xjS?qKa@TohYjRrZ5=n@{^F^@#sYzU8tt=HpHVD9n&ZVk7(}P6 zn@KT~a*noshfLyC7WL54wDicW__h8;AMy^7(=$v(JVu`r*Iuq-SOTfykCZ}Kg8B>* z^O@t%lo&p5zw%t()Uo<&Tt&(;YUw{dSRuE6jLQEl5# z4ZvFAr+-CouNVsJXDy-j8Rmk8rULn*TE(wiQ+~w#q7Io4=Nor1wVS(KSo+b(abh|$ zCldBWrx9!guX+gB8Vwp8mp~}f#U$NawSvBWpk(JOt-Y@5O-*8(QO>Zf&@b$;J(8H# z>_DWMbaw}}_$v_+_qg{LrGIz#>NLMTOsh9{-DzCtkn1juVO7XIR*Yc-N&=*Hs0XMW z)$3D)G*4vHHQ}DOV&jop9~x8O0D?+lMLfTUuU5?Kky?mf7F&H6TxU{Yw#rjK^%#nY5D)BcYwgZ92irdkR zV`5=3jLDlpdBln*M6DaO{CE?RdVBFaxc}nW^fOjU6UVYtk&OA+`SQaRe>5WKg2}w@ zC`ME$O-9i-K;gZ6sinO#h4cPZ0qp3iR1fss=ib%}A=y(Mbdr4ken^Hx^uwgvq(0H> z^|CpHT}9D8_bt{!w?6*QN+TpLtaIVOwy+mm zUFcOPI72P_`>*jVDbA;m7NeKV$40AP4`KHUL>(B`{8dSXSW0BJ;a}h)BBE1uP|q!I z=Qiu#GfY;yPh_ajz(q5Dd7#SFaqF3088`=l;TT4GTUBoN{E|(H*1EO)J=!P>b!hifO z$g_rRSzStl4H%8^M<)&H!QCezlZG1f?6H*@mR`$VndAlN;qF!T>A*B;-&w(;!Ue*p zd}>Fcx8wzY_{{@YTMq0lPQIADgxXraJ0iu`7KSy}gW(hMsha|m{b?7gE_ljNw6jkt z%wXlBQyLyF4e0-aAtT}aD4*TF{lenDNTMQD!9ByRN6#`1rHQ$&n+)eYf*5HjW=^)M}vw6)m!@)s=Bjb4;KjGc6!vGUsQN} zluz)uPjI>+>`(C4d7{MAF5eP=uPwDeU0r$ycwJwU2#-CH!8Hw-k|c*L#ID?FFx}`t z;-xn9Ua}v_^=@vGxfYkc2${=Wb(y8mk!_10KCs(GvSz*|zc4v}X~Rf>k?q8^;Q9uu zs*6+reX3?}+T0(AlpjO{?0454y{8LP08B2LW&NG&Cgcv<9YoUOXMFzUKO>qfYeHv) zJUVc;pqFb?B9aY;2QPG7bqJbyO|>GruHdj|UWu#AURb0<_~hgT*j+;?EZm<9w6j^S z{IVH~R8!3%8Q}UfCckQI`&_o@Qy!Z(LVk4ep88qmz98q<`PDk%Z-0EY|IIcsAhexH z_M}_jzCN}m`rz>spi>`GTH$H&-;c8t4j=BiJ+yaTP)mk2d&N#lE}gs$j6E4(cH?R#63iFZLCRZW32 z+W#@G_urUwSKz}@UmJ>43G2kvW%~vE;r6fH_lv#et{c#PBTsw*z~kd*p=f(ChZb!p zve;;F*D$#zy}8c>vKR5ZU?%y(L<10S>^N`VxTMF+PB4HO6QiNWYlB`Yg=G2LUbXA7 zlE=Lu*KjlpHxh=hI8KKdT_9y)XH ziK_Cdwt&^A@UHK*d%|5oLs)FUk!zpx3@iu!s)Ij!9($gC6fsW-V;ogE&%a_MQ~gVm zmMu#qJ167^6=9;6?yEgxuG#xO-D+&IHIHAw6~9TwLe|`kL+Qzu2La!R-1P`0jGKxN z7IV6>l_u>+;mb?_vL=$;>HktHEJi~>?ry|7o*#PI%U_+uncb36o8ijnyDmJaN;ftR z*OI22pCkeu{xWoZN-d|*y!sEs+chxZm1y$eVrzod(5L>UrBF-d z=7kbDam8su?pFsbVZoj4SHi8(@Fe(Dc6NzjwUzG09kYFA?Ny}cH9YA0t$^g?(MQMU zwxlq+KZgH)*idCXJ_oO3czxZb5?R2hp)AgPu}>!+cq=Wj;=6h>MQ`;D3%z0YJx!Xr z&m9e%>1j&e;sqqJ4V;_qUlO2KW4b1fFW`w>>qi0?4L z0nt(USLXGo#W6^i{}zJ88q&>@AXR-HU+@MjvUB&_HZEKG>d&WnT`)`Ndl>2=HtzOATmM@fgjL@y zJ_&Y$^ELW{1zMBCyZRo*~?V#WD#>3kthnC2av$c%4<&+|5_f%;*hi zKO7S`%L4+~9v`k#6S}NBU+m8U4v$eQkJl0Y;k;*WZ86L}Z+s0b0#JJv(7rjUvt8?D z7qbWeh%1!KGn%ETW0Obf;j=YCE30}ipz8pBU-r^YNHZ7zZT@~V2@BPuUn?S z7^cv_lHIqW&Mp5W1X_1By^iD*2!;R34_8B`iop=?#a|gV3bE6@LsqN}=#CJ_prU1cV=)?NbiNa%V*#<>~?iT`XgoZCF$o+)2sdKs~fKfibe)<45Us=IfG74i;ChU zUcIu+uR+$zKi*{pJ-VzsT0C60$1C7;dk-Bocir||FVuS3QdANbfqTI18pXuf+Uk(f zp98>uD7C@FoV`^aeWb%1oh6)~+ z9|`MQ@*@+3e?CgFaupW1XV7nL;#~@u+UjEZzJ9YU${2Xvm4LaHn3Zrv(AAsDjQ@f$ z=wgGR3(<9}^LSOPM$&Az-VEI;$bDGTS_t}JTUT0Kl9>{XQZOeb8E>|qclT`)8~@no z&juU>x7#I&iL$a<8??`G~Wz* zs%T(VWAcxku|R=Ampt|L^_p5*Z@8sHHDvGe^Ytq??tD|R!C;mL5(wvnLbr# zkUu?!H%B6e^m;&K4ix27tph2IfwwiJE5(w|I=n(N|1kzYDDBS+ulB$}kctb%>vi-- zqG&V@BQ$ptK*~v_$G945WYVN0alI6^or@6h>N$S^^18o%jW;NNy?C$^T?{ zny}Vsq4UuJkrXqrMwYVgyjFX3D(JN6^TFD-PLH0hv~^t7XqM+`FV{w-)`6s0bEI&Z z60TRR*AdPY6QH4Z;lSTyLguQ@oQOw{D8d8E}Z@yK0jieBN39tUpH$nn@fSARPEt!aUFm*~fI> zYD_zLxRMdGdew&qag+m)Q`3}+E*!7>3fy@g*&%a6b~VXWgtxY|(5Wq^(uSa_Zv`At z(tKq3_*oJ?RLNCrDj+Pr^d4Rn_`PKhvx&iwV_aO9D-u zIIBu_pa|s-Qs|Yr!K%5Bqkrq;K4i`BGxEz0FZ7f@&dqaE)_Vmy)LJlJMom|#%X3>^ zw5&-tt(naB_dP}o3s9tCzI@xT$TW6fxB*q_^=P4ovkr$n?w^Fndu!RFXCY-7Iz`)H z=~1X%O$8RDqM>uFsi_GSPIC}epbT)Ba}!uBrI4CAT&#Vz;Q7tWaKsnY6Mi}KA%g=i zz$2};W^reZsyoEI7$};}ei=&9@vo?)?&e$i*#-GCVY%9H)&!a8N|WaNdNk~T z@Tb`dbkBdji-ES9J}PGJzcv32|6!cla@G!eSkQ@!o1b0E(B;|2Jld8Ues7+igjxB@ zHEH@_$Tvx!?n_U>>abd^ef9ys5VDNsw=6x4h(O0jI1E|!5(w_)vb8)V1#=H_ssU$W z6Q`se*x1KK(3`))LOKcq6IQU(`e~^l4WO;RbtX2hZ;=jq>i2MO+E&$Po!|`DO7G5c zO8Qkl;^%b&21c2U|JbQ+9Hs)}eLj$@FHHRsla|9Dr^DnwS_un!%_Ls#=?(R2HtXKQ zo>+4euJ$`>=Q7CpnC*I23a<;in>qa3i3RhP^x@Khg1EUU1KK(x;|>N@x|>ab(}$f1 z--9qw!QV$gtCQk8Bu7CKY45k%gd67h8lAWC8Lr_9s$wOpJ!7(9uvdmC7vyQ#yBD5Cvzr#;6nZ$bBfPkTnW zCC8azXnT+Ic)KU3@_w@>4_#)=JGmP6)wV?Z0sitw(zt+Qt2NL zu2^U!=~=)dMOEcuo# zeoD2G`(W1BpN&hmV`SO|Z6+}O3~v4#coLlxa)7r_H~%m=-n?=?&}UVUN)e_g`BwYo z4#{z$siRxJaLLp`)9;47PBFFa=I_lM8m$f&6^(ezE-6-S`Pv2MXKkw|$*$i`FE$_+ zmmQwTl%toT-RDQnfpx~*WvZQ;oyPgPyc@m~`+O?FS8ll;LV-YtMq?6ZgqhmLoxlTB zxfDEPxMc`|?z>||I7*+qNbj&33i5+b#vd*R;X%NKXH!zSMF!ps`I@XnA3inwI{YLj z$9p21mL?UlhN8~i3jpiLD;j`4t+pkDOBK3v>zxvoI-UnhcRkvmPQ0DQpLNyB|GTxD ze@}#$VWQzkqyl3HiH0UAOguSBVS5$+rGVNQ=i7e2{F=|X?Bk7#kxusB7)$I{%i(H$ z^3^oGlt$_NkSl${_BQ*{sO+>JT$T(=34V9%fM5AThGS^|!q3&Rl@9ux+5E{TfAg;H z+G=7MiEp&kF{M#BokA=pvJK+pjgQ;fLF=8=b((1KA2dYAk8z`NE5+Bn0HQ1fL*`IM zKa2=wf$r;zW!TkKxp<+yYSNgcClxzG3K)<1TY}a7uW`m9d__ET4LN5_Q|X?L`s*sE zQ1f3#_%#0h=Fa7Lgp z-Anj|Gzd%>pvo&(JiF+7ko~M{qsCb8by|O-nCguAv2J;SE|>mdBLw$hO(fgt+t5T; z4CzgGC8BPYSa0DF#VPA%x({UCaNTsrk3-};Spmpy)ci&A{M_SzdYbo-8n5bkr>>rk- znHpIONk%PpJlhD-d;3{gvOSwFH0^aUF@R{Ygo-GtlVj%`dbwF{s8%W$6L-PMhW1_p z%bqK~sW$lB@gRvOv$M0qm5y1qjVbNL;Fg|t*L~1Banz$zv9a?@%}aCDAEso1l(G9@ z>kw*O6p3i}X!G5icW2mSqZ=~{1q^@1OcLvJXPDM}EASMnk0Wv`1>71ge8(cLB0&Wsv;VjX#%a-d!_k#4 zXv+N9ZGBzlK?n^Htv8hD3ZlYHdKk$0$=1p$1%}$KcAXh-SFcqDs)}$S*)z<|UKE`H zEPzpp|1g=Xe&AKTqKpw<2Le0Sr;a`nj7RY|uX*VpYw9mR#Uri_TYl4WkY1M}@uUc$ z93@hpa_f=QBzgcqC#mXp-X#qKLlL+X42gB?9|UgrYYWFFc|+GTN1;|!z)E4LZPNbq ztg=$P*vJ?^ANi1Plwd3wdivB^?yojwPI2%5yi8YIC;0$#OG<}R)lfd!>_OuoN6SSL z|4=s6?_5xA{~aaOa{uZ5`mc9}5M0(qN-jz)bPbR9dOE?-+%SK2FK-j=*^H~E`W5xx zdcOU%BBX>S41Cxrqbl*z+aA4KJ8@KI0|nAlLZvw8d~=MFCpS+jndfj864gJM@6g@L zTc0K6&fn0zwSF2(p*LT7w~lmbg-`Uk7Q_kjjJh=gX2O5GDVlSbLGX)8FW6ev*6%;@ z38~A3OZilZ;?+hsEc4$!Fm`IkL`~6Jv%X7Z`zzS6)L9P&!=#D&cum!wvc}b!ipnYq z{RX1zgdTO?Br(?bnH7zCU&SVU{=Af4PYTzhJe)S7E;vgnOr~nn59pnrlF|SUW-nZqzhhfb6peFpSdd;iV-xR(@`wf0bgm*w6Ed zra&v7xJXoUIPFzCjr%VHrr8EB1Bw?IQ_~4MgZ-HnY5BbG5G_{>RPxtB4+EF-;#GYm z@+hw%LI*gLObuezp=e#58^149Y{sLFIYT^zUbCu<9-A@SDYAfVekZEip(uF1)x3{D zrG>O5xSuxrNm$+!08x#XmgBOo$wW%Fc7i#=92p3A|giDYlQ+rfX8ZC+pb zXKe$kTXr=9FF@U(OsJ}D+ zUoQYA%!K{4f;6BBu`-1AQqe+KVM=Vm{GNxOrnWZtXNu3I3gRWrY}1x3Eb}d~yU{gzDPWB#l1wR2_;lLDxt&w8f;hN#1W9;{xRu~rhZotUl*<(1FCP{tMb1HT&gs>?X+=-!@oNAqi4pZifWPwq;(pfB*g{SoHFQA?eo!F17uROwo$E z;jN{)@Xv*EybZU7N?4nTq}y*SALgJN8>-xg`gHSvi8;$h3|*Os198&2*razN<-lZY zwVU_+ONJf4!oBX8!Jsn{%S?Z?dz5A$JrEp%dw&1f4SVLTbq6ZRyM~^lRk=B(yl%zz z&AEXB3r3=eGEnZ@jBaZ~IbekP&(B{s;~di(a8&D zXYMv~x^}!O&7J;b#nJ0*$+wk)bbuR}sf*VkbLcQ1l^+SN{X&|=cD!|?LJ7ZmPBHSm zYx~{DuD(vBeA7Vfes&KWb%a38C3KEU9`9b>+Ew4gKJ*KA*?=Ktk;xyL52U)bT12Hr zZ-JSNeCg3Pm6wqzJX0B6e>}5ap2!*zoq?>^_OqG;+pCNnZ_G+f4IxpRALfEzU{YD< z8J?W6l_0=e^Z0##itQ;Mw-ykYOtisNc<@|r+w=b9{h+rzl)GNYEh!rrXL`shqoqNl z8tF8<7AvV7NKpbrU73b9h)dZtj!4k4bmWx|m1mg|jxV5w%o~~>yR8UkwQSEjyZ&Tg zDa61kt!))cuYGym0z0LbVSf&`ie(-@`_!%Q5}VDQQ6RYI`Hkb-a_Ngtz8mw>j2$}z zHB*n<=RtIj^VLB3~Jh6dZydlvGU ztXhi}HAaU!3#W4U?OWAi7xFMW- z)0m)*&zz(WIbJbuW*?m^HgXbl2&J$m8&;~XH^$40Yb;y#?*PadzZ-a6Cs>WpNNHT> zN|SzgS5T9*C^kq$R!rO8C8#Q#`0hbuoeK1tA)*{6c)Et?lh|pz`_p zyw;W5xu|RDa@@7#q*+5uwdZ!3Y%{*!Udx3VBx-oKI~`M2f4puDaZ-TrMG42I1a2z7 zp@lF$kv130a@1<7Uo~$Cvl`bQd0MN8I_+2qtV$u|YdoKZpqXZIX3;edgKL9HI)> zu?G!cDOP`87UGy|Davd9G>A#zE%4Z}COiy$losShP2~oa$fNyV(W;h!Q44dQ;o5O7 zQ;yL#E~B2y!KuF@pfsFkkckfRV8;HR96&VhQ`Y^?`#6Zd?UtwyNpx!kH80yZoeJ1; zoCmBhc&`rLpNZaOk&vlU;#>XLWHOYjtI{<5&ymRXs5>>S&kEV-XKSv2c49>D;C z8bgrO>%7?cOps%!7``MTN#bjNEmw*|>ioSN&!sRy7>hfux3FB}XR)ZFd2Y+<@udtP zK~dQsqme4dXS#fpq#szctT;G^jLgmRO-V>ubne^YmE<*R=97rS%dh&VA^esp{uscd z4XJ3fsWpH8y87nRPzQSpSb!9papd$*8>EobtP)oghW3GO`Ua@J`wr@64J@Y+?S|^S zy(rlo!aebbC6!Z@y4DVULchQa1QWe)c%4PW+s`wwV5~tg0Em}Yx3wQsYx-J@ZudEz z6NH9AlQxKreNtHsoLxf|Ot7SyvB8EFP1K3aH&p>$;%PlEsCivN3)fusbPr{G?y#7G zY8{&8wpI_TS1(2lNNd=~PP`0#?`FHz6O8uxIFbM(bkXz)ilu`}Nb|{XR&9=G zKZ@vgY3VzquLcc?kjcfu+it1QZfTc$Y)gt~ABSl)utEfi*rJo>gwVcsS*n%!op<(U z*U=L3_9~VWvwW^!uJp?XUPPD=LqV6T|4LRdWDxIyZOvdFvxz071Gp}sN|{YuxDZ@m zJIlA&S?WzLrpPQ?+RMY?){H?1rSFA>_R18T%BPs_=Q@859C6=!Gz{l-de^tm6FWgQ z!p%JIXg);8)dF}H4n{?k1g8o!2CQoSsVd@s7QX3|nLYu`f=b1Psselb+NxCZn^N;~08ntkD~FShQ}X+YwE-?eO+%G>B#H{YKT4>GM2?Ihrh*FG z5so@5eWiBYX{*wV%s`gSpF?eNoSV2R;tUTWXj&0nBn4b4ftjdE9{1GHqNzqjW54dR zq02olN??*{Vu_wpjWbf8porG8TWb;VhDYL$G5M8rgYoFat?*XCyI!t^8x2v}p9nbE zh8KaQ?D_>94bVQ7i7;+VL5j2O@esG@5#g+0P(dnc=ShYH@6RVzTn0xaO!-4Y zzDCa~FTRe2B|KYiW92G|6ql4xB6v;j`9?d{+&PNRvEajT+3hd9hZ>Dc)sNPZ$&wXp=l_SX|^9SjWZeZGShYF5gQ76u&z3 z-DG~qV3}6;~$(KM%qk& zYfy&M4PmdIR}tYQV||dyUl$`)%&V8HT2?NJVH;+#7uTUj^m%GKC3BpDC?T&{$DgBi61q~`>!Sv3DP>>ARb1Q>8oon#qCw$R7q7wH8W#5+2e(n$ ziXP{D2Yleu(c|6Y=u0Gez9|AJn>@kDle0i&4{z_O;(3?s4Li z>AsmQGb%#HCrX&uM#;Wdg^7*Z4=UnCtK^{nLO7cTUTAakA-%?DEo}mDw3r;CxYxMqbfL2p`HZ%560~((+%qs}6A zpGXZj+*3kcg`Ub4o}6{3$N%_SaXK)GVyJ{FrhKd*ZLJylf%)EJVxOD^abZomB@N1p zQvtdZ(X!#P$CIUiNHW52XES-dkJh>$2AnXoB`voUDX!#wQDM~{lymJp&NW8;=ydWSXV*Ndc*}WvkSLpPm-~8Llf!7^`?*Rx=US#F8;D2-$+)Qz96gn~|f)|?<+-JfoG%sFJHR(oDIXazUjIF=aMqM8Mz2S=A67D>vMi1e)9N)ezsV^c()tHSkiEhu&|NTI;Hq@<^ zVd@qWyPj!=37p8HRq9Q)0;a+8?C2c$y8na%mCO6x)R$icJ|oCfC7=A%<(=9K?{@{& z|NVfBucUWP8LA!1)}+2F6z&bWAMQL}%RZ~F3WVEu8<#(VfTu_D_w@*w65G7Tn^t6W z<+9yS>~l_k=*<@ZusRj=f{u7wY~6DB3w_W)Zj}Xm(V0Lp;h9+Jf;U=Q&k~x5`ehFH zh43LydHr&6G^XCRbQOk%Sd^KgtmLl$YuG5$cg`WB*hgFuHhOpdYq)$}tC#n;!qQ{# z_b$cJJRh3a@uUSXk-W3d=N?B5iN(vA5_Oirpfh*rB;E^2u1yNrC z_OE9ok7kQaMMdRm?GPy5tK+|(Q-`RMYAn=0Sm!*VJ^$uk{D6Bb7gV>ku7ZBMiUuMz z(m+GQU(#3hhChqW2pZzis$kES;DrKjDk4e+LuzEid0K9`z;0zgNv`uOMv1(^N^7~ z?1j{i5bn05T4G2}%hp{2)1B$U`v00wQtBnO^S37hH<-NSVG)n$G51D8C(~HId;20| zUPjLg;fb*iArXiN@t7F*4;hxW<9_In;X2%jkc%@i&+IcEeLnPEwY$B+7%upZ)?>+C z?_dkv!PM;5rJ840Fe3+`j%k`M;*@;cEYGnttMbx28}kpL;;lB|#tt!$l}FtRvfzLQ zN^&l5nQoi;`8{j(&u?HiFJu;sj&OhKM*~2cZPB1sg-i#BMuM0a$Kv9WJ@0g`v;$?! zbho16#ecUer18~5)O`%zE90`>u$59h9tk$r3zML;W{I`)Ah!eg)_Tt(J=DP#7u34a z{5(P4wsWQN0pE0pIriLZ`){lG;JC`eGC6N|Cl-JIgTB0ewq5C4XC)$q@atm3_Q}pt8pYIS4`!ps3&F;84 zP;~--_solKNSyC__v7h8kd@5E|12T3+{OA@SKyA=cV5S)7bral;v`z@*5;+D5~2wAy1&R`2qW6Ym#q zbpRbNr}s8SjGgx7dQXfUqxfmJFsA&4d-=|0goQlev$de1{R92-aV98g;pf6xxbUPq zj?L=?zs`|ge|_U6udtUYCGUTPqT8lr5$|(ySH}~Fy6EM(rVhORwj(f>y^n>La|71p zD#sBo2-gfAcPFb8(2^Yb*gZHLD>LL7gNT0nFzC>_tF0OP`_;@A{YrbP*vzM8Ne$+c zkAg_|O8i6!Rh5?o2hAMlGhn#7ah#4b3Ou}`D6!TQI5bqA+M9d-AP<}J*QE*e?mYi~ zZBz2;D*po`%>EycVKwhiCvSzrzAci1WY89%9Vce?!_-`ZLLix~J_VHJlF9~BY%o_i zNYPZ|dVxU;dC67L=PBEDDG@aOkT6a*c!TK|uS^$GEAD(vL+_`yEn+@MU6}NN14(L% zZr9Lq;Ok17jS--H9q6~;gpfb!mz?w@mb*-Bo&>z!dd*!osA1t(Ru=zB1l@VmHiKsA z{wIS$x=9F=azy-Xc8Ru}2^*T4ZjJ^$z|@msPp3NaDi#tlzGpI~d?z1C z#R&rwZ?{lr_^Pl7y3g++m*@dLk$1-ra_5AEx|wY9$c0CrgWSph)DU!|F}`UZbDLs~ zUS)VPMdPWnt*zoLh@il_7aDQYPLij$7EuG4Tq%=s4f@lQ#y0tNIaYWUQZ&b00?D8Jms&>%ah&T#m^|eW%obu@?Q2lA(%iyU!XmP-IB`68jdIK8X(Q-F|Mg zipm`+N-Um!32IcqJ7I{J-F+?km3@wq9Xq2@of%Kx1G7eqN5H7~V}(igX;nMZ;*IJ2 z`V3Q$KWWO4oFQLApsg*1x0@eBR=iYd;%TGIX+Qbc2NP~2tLJx>#5 z-F_R`EoDT40FLD3jZY)^7B5m)!r&$j3JbEYP4N~V*N)kXdVbr9Q_eg3vC^o#araWm zEk~43)uA#Yr^4lfT)72sW|Lls&M}jwVCIsBj=$Ev4O9gfT#cBYDX(rlcAs-Yb>=>d zAddr9q=PkbJQKJ2hd_LkV5&ba0y^$hJB2SV|s0n`N1+h_KEwSxeJE|4Q+4bt@{qUVHkQKhI6)ihvxp;yY5> zx*Y=BdD?xUUuG@Z_qATvW(DUf;{B?`ckLvACw>2-Q%4g3J&jneDm0i z2!um8-HU3||4#hQofw;FA!m*3^fuM0pR);QQ0{vFvqRrt0c{Ce`pt0j2_C|MaG4M+ ze`i}aKavIBHx?F!hKy>qVQp01_v1*w9uqU?36}~c-2yS}0S5yY$+Z4wwb>S%Hzw;ER;ay&FL;B^(F@AN+&`%ui+?V{h=JIRdB%&7<^&3hm_&5KT0$ zLwLO;BO|QCCy!oFnJL10_d+d+3sy07^^{7U>#qE2D%TsK1YWJo8BCI63se3mQc%Zx z8=j4=L31|wdeJ%d@tP*dA$&0Rqt>swH{h2QD-fNfau8fh4|UF(3aSzhV#t9fj-~_r zTqMvn17R+T@S=^_?S`ew`m~p->uYN23t|27+_mGu5~h~BD~aw0{?@D+wtG|h%kKQb zjsw;pWYKyA^cs8-pm_6Ec78FZe4F7WwagCB{{Vpn2rd_T| zA0~EC{z?8aAfB-!+fD}lZUs8}?qj9z>1Yt-<8_E!2Zyy9C2eKgX9tg~#dTk;tI!*x zyyv$qh_egYNN*KrQN8Oy>c{49NVzNtissh!#(Whrhoz+HJaTEZ@XapCL=W*aKdoTjm3LQ z0^f8e!5_nkMiNwatPQ>H&^*DU=YgK$bdu)twHOg_}nAc~9? zxqYWbI>H)d!d9A~ZrbZYv#_lEy}|Xn{dA$m*K5E8wyqwhrc^A&q}5|rIS}l~gDSOu zD6;&b_l0Y!m?5%j!6S42>krp3Wv-V`^RUw>0ckxnrL)ytJH^SzzuIm_s#AGqSl#QN zI(6m!a)%zLXME4FE|db+clDxVC2G$v9$k7T|CtV)TU=`t+K*I91Q|58PdyzS9fe={ zb$YM5t-@gsCeA)6JJdd+yTeOf^6_J-$lYDo*&>8vkf({$!SpH>K{O!x$pq~*7?~TD zFok|vYrrq1_zbi08r>5+82xX7GvhqHU_MW~@0VaSIlWkYLGL+TR!(pi{6Y#|X)Au< z86B$DnaBU+L;h@E)c0&=9B=5A0W=)yoH=!BnbW5x zf4#uheESzSg$#oANK78*ILusak@T&@0`K#*>N=|?_!D<+r~+3Xsl2Yo*Q&x6`@2bt zz;Uhg9KGwu_UfSN-r9on&J!vNiB5Q$U=&sNX7i~(fAqF%vBVKQo=o~*{#+pqD?;(YWaK4z+$|&7t?#q>oQSn&!TK=-6C~b;{LBi&>9nUP@c>K zXY1zffwrto1lbf%d-vmN#d4yG9N5YPXQL$$ZvQDmI+{0qnff9~~ky4?(MF)X%J-Oh6YT;9v|iTrzFJ&QHC^?5_hGM9@ea_g(U zvk{%m|Mdb`$BpcY@y6g%=PrTDYe$xrq^cnGb@ME_?s#7!QyVE+w`C44x5f*gu$Kb3 zM5^{_NdGFOiF&jgZbgZbFqYL`ZH+VEt!-HXRdpXrBY6I;2HhT}cQ@a*cwq?ouHF2q z&++b>dA8u9_niAvsGeaNI)v&eEHlO85=YqM9Ika4CRa7vgCtbEaYDnG_(Z^RG1_+W ziadp5iTwCeQuo&Ri?Jsldu5q?HX5)mov{!r$KE1Y zHuZV}_{-^Y+?4>2<+ZTn>2`mFw1spAuXabbY4+{7W4&)YLq{sr{n>IYU&L^Rq;XuM zCGmTk(?2J|O4W^D(s@aO7S{hC0AE3%zICReUE_}1ce8iT9eQ!$NU*+q;PbX^UFy2I zgZbjvOWZ>B9jETxMrZ9V78j1t?(~PDrU`ZBP)M~{8fATLk+Ja^p8PYv$oFr&oUeWD zOZ@Y{U3=e#by7}XLml8=*FU5?@IZyZN7xAfT=BJk;OP81X_}z*KxkAGg?*AZCP`v! z$E8_cB~4?(phqr0!qFp#7%AteH9Cw|igda@M;F#jYtIjnQnIvS#@+|*$Zpq6uPP~t z6GLm(YWF#1`!w}tmvYe~mvh-NJI2`L9J}v2nqGOuw?9)Z=iYtk*Kc}MVCaun3h>-# zKmAvp@-wrJP7`ctP+ERmr`>3?dGk{tY2$fYjo7D-QQAWQQrKu6P%i8ujhh+tbB1ou z6yN=*foGH9$0Pi(P1T#@i=X^_X8e*MPRP3!VU!Xk2}zo1{AEd~tpwTRFR{*e{*)w& zP1gVowiF~GjBc5JFMCg}5T7rN|Duztynf5(S$5y_C7yZ7FHkIv4xjh?9afhQfea{%n$a}%4lJ&C|S9_@{ej^c_2=bp7)Y}>ZQyYu$q%UaFai*CE+`ebTq z(tGB!UxWykIdI_a4QY-ZN_knTS?;HaQ0v77-5Z|tRkt73H)OW#;}46@~f;Oo?Su8 z9C6$M5^~-oQn>_4f`#GfbEG7Sj}LJhm#cxZOhy|o)QQlNR=W@ z8K2mM-`vk>+s6dal6T(ObA`!qPtEW9 zHv9J6Hk3FMLXh`d9LE|?Kx(a7ICg|fUhoEPyzU#k<~RO;SHI!C!=i}ZP#+mo?}pc! z6CBGuul0ui44&4*pC3H6@pl@-=Y;1s{%`a>9@EFKH@sK$@RcXL?}vPNJ^u~7=`HVN z>*f)2zXW|m#$cq=lw4s1+sV;vtPeF38?A1}QJ7L|beNf{lBSw+DUTmStgW|DN)0K> z3~E);?FCdu3e=lM!5W~`^~vR24jf)4juVb9)XA4N^)LU%XWyC6xi|1Au1CZHT=J}^ zT{t)AOxdnQvFsv*MU)!QRL(I)z()Hv>aE=ry)E>5cY`&8PGgiTAcckFOkr6gS&!O7 z${cCN9gwDdqSU9}TfuXtux*DC*CI+aT|dUp02LaBq8)>Ot!%W{5`tJCcM>`=UycHy zB#tGiOi$f<&9yf^WS+S9zVlbCk{Sq_2UV|L4F zJo9H?!!v*OHN&ufVtV^9GFUjem$8Y>xL%(9dv3~3ju5}!;poBLRL5qy;p)%P?>4#h z=4(0a)YA#W7=fUh5n~utUt^fvzK>&Dc&@`(wM4fU@RC=)ovXh2X@2!h@4tuP+}jD< z)3Edg1HC^dpzq-X?&%PIxD(iDv;e;`Vs;Fu54a&v!pGJpRE{_LOP zR44l^+evHn2Cidq*_S^?xiU__*Jl3kas0;N{kw*lghGq$t&MYwOU}u+&EEW z$V^w3j}pfz%|??rPH46JBuPRm<1UEeg!zRUX_^kveOfc@!T{uRF1DqNriGM5QNor@ zWB7h(CKbbok#dnnHy59J=F?k+g71B2w{_^Z8YH6lSI)9X_Am=jpuGg=!hWg5$PU_`&O|%fv_|s zZwt0nlWjaPWy(89T6T33OtdfRKVx&c-R1g74k3 z=hY{>2N#~Z?WhoPOW%*r+I7Y`;)d%k=hR*2ux0KHM#pDaSv&`3d%d5+ z-~%BBEolb82F7pOPBzFSxa`|E@tH4N!5e@5#nfu8EK-F=tBY+b8m%6sqDMayQ>`_+ zIJP2+Q^R7N$<3LzUxd+{OosC4{p#&ziZAq=bxk+TS{}%2_O~ZT!keiB~KwOL2-2IilfI?{^?}*;hO7z(EFLEo^^QP z*rBJo`N^rdEn{5y&Cjs?lrt%fjL~eYu=Df_sEkfgC{^fo8Z0gBr&V8Oa>k?rh2jXk zt{K*8)>rAYYjj#Q!q8{_&>bu<9H2ZhPP4Jf!s1fKg6j~+DRFGTBtaPCc@9Ak@|rik z4=E+vPdSTkef!pXKyB~aScJGoHU1HF0)uPc4~gT1C^7FljuXSj7$w7e`60CkPXab< zsg3W;K%-5!@hK0VSH>e$L5b9MM5q&LN8omd~}NS+A_Uf6J;m3&X{2ZN_<>* zHlyE;5JIA4j$W{cAf?@|lO`!+Q?t1C82{%lKVv5T^v0^bsYs_;EbA(Ttz?!DLzt$S zzzF1QNs<~WaDY-`8pr_&c<82_Q`*zb>`%o)T+5H^Yu;wT}CjS}?3Z4nMm{^3l7Wnn4HNWaJF2@XIA z`104UG$H4VV_V~lj+*>PNy`)pqXt4M(*e+tf&QkT(*&(!+8tB>$Q5!N zJ#>gg`xv!ufXGyR2N8hQnjlJWEkUF;ev+UyC;?%T;tH94*x*MgN(lTop_;czGzcdj zTzS$E<-B38e|Z0Hw(UHdR%4CT z<-_FirQsx6b!>*KFZ%@BcAU-H%2DcT$H?VNStp=HoTNi`8#fcX7~FW4rRa8jwrrh4 zYt09L?^lO;wAj!}8@AQ7&K?sdw$%nEvjNSwvDJ2eEy96NXJ(E!0so=b3+^`#?{xhW zo@;md_xswBQeOAE{sxZ&#eD8KtoVn(h6nH4l44l!8y3OD@o%i`P#EAxME1frz3tEV zn-9GMd+$M(78h7rX%Hud#N+6KkryyRt3G}Z4S&x7d{rGO(CYYoPjn3M)s>8rH08jGyWh-aFoQg4BF3C5;?pn3@K>rYl@>|pM0b?^cBDUUv;mu z{#kVV(UtXPyz}&@a@{qTQCpp7W$_RXV1`mfWjQ7VryyXCYDhPsCBxJ*oKqt!H| zo8wbk8L3Xt?HoT8D&;&vh#?QY);gobN(rNwXFTUseEBnf$KQSGru%8NomgzUR{>2w z`0hX$!~|h%ieDP~{ZRD#q3HF43wr(F5d)ev+da{2_e8U0zR=L=_38Hf2P_Pl`#}(= znmD_62F9K0dvk!Msc`~wgQxgUZ~y<(PrPx2k8W66T@sX({y0`S@l0#Ns?v-7xP#uj`zovWpMXS*84{aQmnT;lAHQp z|Lo(nz;FI-ZDsx|wN{X9oja4SeDM>kE*)fYX2q4E7t^s}!Y)s5S1^+dDT6Bg^&#FuDK$hBcDgv2w@E&!M)zyIL-t)Zw}iYL+hA0ZW}^SnWNKNBuV^i0?=Uo zV;}Q)kavK@bT)hy;(}YBqbK(d-G(bh|#Cu796SKuKvN z-^KB&|NY?s*w9tF=lbp6{Rp{SF8dr}{Hznu>xYJ2I!Q@rdr8=gp(rG~-}~r^z4eFW1n$3|ZmRT#u{j81aovsk5*|mZ z(d>yvvnvM3x_deSDUSa&N?F9o{R;yt%NhcK?z7Hw$__3(ZzrXq(IW^#Gdf&vcIf-j zaL{Ma1~g;97S)O&P(5^XRnKfbz2|z)hrW9Gt>1Yp_wA${z_TvCNadX9;+btTIAxE8 zdBa&aFFu)2KM6t}9A%pbm!+iv^@ey_!$yKiM} z`3Rfm&L9l>?BBmH1EVbAxz4a{CWN7ys#c0wD&X_77hiJUC_B9&jDLtuAc|w+$S^F0 zVJyNh7CesEMkmne_EAEhGW-Www;CKG?|AS3Wap`;vSZs6>-El1 zYjRMKPBYF4*R_#SFjCIb_l+F;{zFT8|DokQH{E#MFF3aK^~ZX@PRapTN}L_7H*=m{ zA#VA&IYqbD$-JkHvTXdWK|yUkZJgD+=1nwEud`)t23vY0K+)TRB}_*k0oKrHC>nNlWSe8IYIVAXy(jfh`))Z`ehyieHNrK@EaBYbY zk|+UD$R$aVKB^*-|NTS%x7%tgeWvPs`n7lS)zAHJuDxZE6XCb_ zK;b=5Byf*9K%7ylop<&&D~ulBhJQ~d&}epr6oOW#PrKV2{+&u$SW2OkU?YIh6#Y2C z@RRudqlDl6gO76Vd1sQQDXwdiB!=xrYa=vc7=C)pPLDD zeEo{=U-6Z1-5mZ{Ishrs7hmw)tt5%T``3;&DU23bU1+ej*uWMRot7c6IdsPoZcbs_ zRq{oTcDtSR?_=VmJ&X=k7aB~AZ)MZ2F*>b)amTSMMsXs(ck}*)AH!8^bVRMu5dh6j&p^SIKq{jw zv@yvUMEpq{8&KH;L;-{Cy6C4*r&jM|C%?e}M6vm7q?D|#H_7E(6BS4mhf(~=%fIu3 zPdr}s=%gHgNc{hlFM7Dn1XkH&bkhiNWWWx^vdiMa8sjq+O18zO%~eL{wot1bpx{=s z9JUBLrqf#-(tgeDIE^H2V~G-R6k!REAYLO#5`r)pR{w<*BtRG^Xvjbv=G5ql5-m`cB|FlRAJs_9T>2!!hEq(Gs1mKO8U_XfD;%< zbH#BY_;;|@YaOAKqSf_TtF<%2Sg|23(8JG*h8gTP0V>(P*twE>GY`4P2{=W#@>)Hc{%+^;d|qn>1K9ZNS~v z-!h!^OH(80NmdASEQJz+oMT~02@LrD^$EljL6{Q6+JJ!&%m@0KhaRoG4rFIOfAjtfW(LVuO%9Q@L& z-p1Fz_>cV7yZ`2X&~FbV9Wc+wNeWv3yD|R3T3Kz1Gfv-PNwFc#$sA#t9-kiFSoq(V z0;FkrFK1u~Ln7Yx=9f}$c1bc(64$XAA2V|4)sX^I6C;dd*p25t=UJ}~!}y%HzTxM@ zkEH{6?z1m?>fGrQ<`f5(_pehs+N3m9V07~c-ImYVVuNjGpF-I3Svs;xx8;MdOchzj zpyT0$Aa;&^r%e=?$J^~y+^HgQ)MxiCOXil&B%_2heS4jzLyE6BG5S9JD9(TwM&wgS zK|eN}0q70%;Ep1fm!Rw*oZtk|kle>%uQwR}fGA|}y|OIc_uu|ENus&r8E2EGDeJX1K^SGS zbFgL882P+MuOG5`c9dMswO{>fZ~wPD_RKp!mJUD>|D{(@c-~eT>m8i3$LN+3@e5bvmAFc>Vf*#G#|BW)3BcX|}q=al*>#IzM&ZlN9J;yVF1a$I=1h-SFI?pAZC# znPEp*w&DJt+Fl`wVmhtB$aZCgL4a1hPNX%;vay6qsxxC27Wtw@d$~zJT%)mWAjNho zpdCa+X^Q7qL)PEHO>A2-JN=K31N%{GiaZEVl31rGAxRQV!LjIsF?m}N#US0>cOT1* z|C0~@-?dg_`JeaQdBge*H{R}#&YY(wC#oEsKSmNqtSm1L_3q=?5J^~;B92q4)e*k^ z%}?{2@A&YE!!Vqj6G#(N@JkZ?@7nk`u8mGWiUGx0mJHp)3v7)1)AZh7pZx4qq*`8LuCp|M7v0vX8%FVSo_F!N`5!9>@a#*Tu5_no z&up5;QX?$yU#GF;vo_zsb}fSeXqnDHuj89y9x%UW8D%MS8UqTgWAbj5wZ#VAb_>_8 zAam}pbyzIB%-8Cf(vKvKH$(tvEDVRgr4$>P;4CF@l``zW!-&PSdxETYE``J?NR;FK z)nmQ+=bg1LyQE{ftX7AlVkk%bOOgyfWe-abYNiMgW;gT^?j||cJE_uZY#bYvT0@v%TiQF ziX1$$!ujXSnGTL)qm!7sZo5Lg@i%|xot>V4+GD*34{03ulpUL2T`h($-f{Z5Ktj8> zhF5gSmveNQJ%pbSr4f^x$8kNET){DuTFS!lEaE7p+vyM|5mITKyrQ+j2g`I1`D2Iaox>( ze&w;={Lg&xDz3inw$8;rb74M-qhCDhob#PqZn}0*fzM9<48fR9`%R2jIdX6xZ+zRI z-v3za14IHR&gg^IKY7MKSjB?({(e8i%elkdInG0Hd=heF>+hZ`j#KX3bCjn)^(;yS zn`Wy=A@7pUx$K;q8uB(&D@JDh!Y5xOR@d9|rkie>KljYJ8}2^1^q93-A5sM1*!m6Q zlSP7X6(L;QoWjj1!tB(q)jC*XBP4Oe+F}D`c?A80iB02_OI7SJBOzCYN|#2>qzl+Kt*&V+Do2^ZUk2pSXrv`b)08+#uq}bD6b0A9Rf=T8C)5pM(oBIx zDT4QjsO5407*na zRD0)1)08MqC>6b7JGayIx$E|u2|7#aHNX0%ceUF6?LRgtfY8y|EAxgCrQN@qpr6oQ z?lQW0gz2pl%$+p{tpLl;F*cs3QCr7y;n-dCEY2^Xi#f(;#;}x4nnVP>i2Q_yZP`R| zgyT46>g^3m%-Pi60J#}wJ$~0wM6v1Nc7vE8NwB3P(J3h@t|dt_=2o2w9I3D^ zNv>Er@_4xcyF<0W35y_JQH2+I&TkaoAt}`gcjw#Ay2kF@?N)e11b2KEU;Qo6*q` zLVrzGs^gv?gy;UoYo0BBEF3`IO-hr~d9;q{cTOZLbySg7y-sza0K%fv4Zv~ewL>O1 zj}V3-oo1IPHhF%t(WFo+VOtK}T8D|*3f*Qv2rTWZBQt9szM{ zti`7kmJoQ##t{mwOio|`M5m&@gxv(DTlT1|rn zv@C^`0^2qjS|RUJ$h*Ac<-ds#@z~IzR;&kW);wTv!f4}b& zMIliXp3n&xtZS~@&8equXMC)L5Q0M9V|lg7(n^Ezu`;vMqa0gUW$V^0{NSdqI&XQ~ zdp>;EzGKD5y#u)9;-{UbgjS<-BPf}pvECt$B4o~ZwpMGEe9^;mN|5^Giyq~iN7{?= z^9LS)H1oj~2A?qg`(A7H_7Dag$0>1?W^BLV{h|T~1;Q}aeB;Vn zNt1*#PTS1k`Bl0-pP8vDQ5>_p+C)i75XQt|pSdlgLI_a^qh!@c&kDwheFVyBc)y{=J5TH(Q45s7+DtMV`W^g!0oqQbN|e_ z4^mRg6iuJ7{rigo?n!GNMj>$=XAU7gp(Zded|=2lv@vztzIAHo$hXXnGdoqqvJ~Y~ zj@7j~Tj$OYmQqd>CqMQ0cL0i?+H^`4sXUes86LELFXG_tC4{i3P86_g8&FKoP9cOv zxX@(r$SSRtNf%ZZ)|j3iVPbZia-|F?$|F@Gz{Y0f;5yw}hh{&_Ai&v}ugEC96Frn$ zl4RO`83AP{FdOYki?(kx@e~F%ctYz&+K-E>*Zbb}8q2obopIzlNgSw!#T9}e%ILf$ zovu%{QY20iloUjvj}Y=c=(EK`*46t-uKGXV(y(4@5k(;fB?3HFDGK%{+C6Do$5rQya;qVH|g&@^*vWdVXjfkQ? z;Y#03@0DG;P2bF)lg0Re%7`1K5~LWqCZPmWJdgGSYK1E$(jtfwy6t5QA#_A z(aP=vJo{NsJ@c`=&xEu_QMnJzZr*M!9^FHlYKjGK2>Q`lpFlHREKd!2?C#C6|KMr@ z0}8b#*8Q)Q_2z&N^>_(z029`lI88IYzk3`0#${VJj%~5HTxV&eLEjIDh9Ac%JLaZY zTRuc>^?>;8-+A9}_XwG$5f~Xvi6aC8*?GoI-K`B^N(s>$fhy?)Jyl0XUO!HnajfOe-(nhe7H4J5P=QiePiJtC7(nHU(PqYgt5UWuZRIY%0@hhx9uU-Da2CQj10u;R%a; zwLm9pFRnDZq_N@o6Urd|5`FKj4pWU3=EP4@gAUBu3O|b;qBsFzl!09-v8ADCc5KEk zyW+c#c^lAnyxCS`*|sbt`+hiV_1U(%SMT}Nzy2OG40MA2_Cs?5X_`Kf`aj6E-slLu zfgw3gQ{q9g{~%?^{`{{$!;^OHB#M&Zgy2}Ugy-3;*NvFyt-J50Iy%Yt1HB-qbh=Q)yZefzfA$NC0)_uF3SN~vax#j+)(63K=!G}o~a0+f?&TfFl1|K)_%o)8;G_9qElL(UUuqpzk;OPLzUQ)0>?6v zV}r5nqYLXuA+RjT!jcgW?ezjKIR6X|?7fMww=AFfw5R{)7r*??-;bjBzrE~5Py6GS zzxblJzT(9fJ?j-OzNk9*-GBJ5Uw*_tzXv4@BBhv^+FqqrJ3wW+1Q^neLfK<}?-Jvi ztK@BqRxidWc|>tUb1g-=;5Yj$Hv8m@E@9gz3KeUIkCD&Y1c6TyCurNE-H)hF=SdEj zT0+l{uxtb5Q9z_qTxmK71F(-HRaV(HVSkhutai7bkarYPX~HDMQUZ{aCKVid9Nb+( zl!VIt_pRIKfPmGM@H5-Lg9zcA=%2HAxYy(tbi0A25>O^M}^4iwZj@2pTD+kvz4v7KO!^WCHAashi3e$c(f!kCx?zH= z6lszgnXpu&l)zE~B_w{55+#~~Bd9GtJ`ljRWE$BE*Q!YM_1ogP6qW@5IC$k`OSK7J>n*VT+p=ZQiMt$;Yy*isOt8a)X8rNPAu zWr}0cmRQordwG@uEr@iAtpsT%8`h5!GY}+Ax1blr6y3)K2Lnpkh5Gt}vK>dwFRTu= z4B|N9z=1<3Wrjy)x9%ceDATIf?sd{{j08l+a%1Gb^u3&f$zPvv0VlJ%U7te1yAMe< zkugyj%JG5DfEtAVmeHJa91E$eA)52>{HhTK85`l~!a6&*Z=vr;#F-TN+IpR_(Gf-} z)pT*kB5iH9U<;s-1|KMSF^QOty7s?Z9p*$UEErMHbyzGCy_LrZz zPb#@LP1F6htrkA^&zHv!KLSXjpV~6Fg`;;KGPGZD%&F&Zrq}UlFL#;PF-mi-N2)bZ z95Grf)2wyqb$i%AJM7^pi&m>m&npqHM#M=>zU0tc?qXw^>sB8r1pPEY0f`cs6A;7v zO4$}coPd?$S;}-B(v*U$X!l}@t|E$z4&dOPw***HVkzq}kA;8xO)pVOS!1?sE2)&U zlqAV?=A2TFPS@x3U1zd)&mHW!{d#`>WpC$>)>T8HQ{x1tKdtz}t8o?b|DuFV-wI)%lBMJC3p^m;u?#T<@p zQLR?Uc{WNZwr`tZVR4Ck&JcY<_AIb#e0^!D1V|9wRFrg)tAQB%-Zow0hW55|fcIW>VEjVhVe4oYEDh66;!u zFiy$Y5=WV~j2|T^A&?n)u#(v{psNfb(6t`*D&W6->^^$=<`?j0DLC$mN`yn~cgnt9zPY^^DOAQL8>hL7j_izID zRTw<}#PLWVik=AnA4ULx8XzzQSk^#MD2oCtg%IF5Hd0C)%R*WLsg%KPXwCH0SoZUR zmDL)BLJ=tyON$Hi`T?C*4Xrh6s|(cX9ZoG)snu%CZYq+?mub|N7@yqA(y_bQzVmdt z?K+b)JMjA*W;UPB9lO6rA@7>$!%`I~C5_q=)v;-cV z$J%A#I4(HGV`{DO8+~jAlXFFGJ6yxEByp4&qfa!BZ9qIZMeZ#lN* zN+})7l4^2t(w?227PDiCmchJOT0T7FHS`0Mo=r|p5rnJkIOS~S58ui7)Yf5Gc;8Oo z-ZcSJq}t#Fo>(Wnq=0U(&q%pwQqfFN$g!0P!i2zeEF8-MA&l`$Wok~ALL*pOUT0={ z94Qr!ZBeV$ab25ArA)oqrCgabjKfL9$VioiV@DVp8)J3l7?sNCP-JA&)?M_v&5Sa> zNNvp!$ew=2`M6$z+Uh*{g255BnyVyn#IAFm$y#&Odc|ws_Q5N^_VLdE@k4e1mP%#V z^06IgEO$uz=B7P#hrs|8%PxK2H?#Y`;jbHRpaY2yo#h_0J1aC7+Smn~pdAnjftPa- zLXa=ys2yH6q6}Hxz*Y(=%|MV4X7EA@6B$@iA`wJs3L5gRMK_2k7cIKoghW6ZY8+P( z^b&Heg`2k@QR=1lyz{j)x9?fl_DAo1%af(FcinWu)i0A$I!Z}YWI!K-{=J0cAYp*SzSIvWpsKdQt`u`z5 z{MBgn#Mo#_Tb3Ncw3SjIgpsJrPJI+uN}`l9Eodn+4odSgQYsD|KE_D7K)GBbi6ffL zHpPO+!Grsmo7;g9ie9%xrBWtMW1=XbGCEBZ1@yWGPcTxQAc_?LhDiw`{Ig42?dN&&RiqSuQEdjXY-N3Ulh>0I8X zTkDW7IrLf~_z7Vc(eIn*t-M9A6;P_?adQ@(W}lUQ#I7wP1nqz%F|^5kE5IunDR3)G z0c2Lawxl3VHDP3M*si5;9Z4DrTw4%CCO+;3F+r?JIti{NNTL+iRrr2FA!m^!8lC8e z9&*Gb?Z%6zgS7>c%CEYwoIyg-o^7wI2eX8u4^+rSz)c# zMyHw}h_aDrn4YXqYjh9-s-qJ$8|wr?gpv}=a+sRkP8=OC+&*w5aAFHEj^ZaW|A)C= z__G&?@7}m)h|V13>rUnnESc$4DpUQpEs2zwW3XjbuoVP;kDWWV(eJgX)tYSGww=nT zi5435WtJA_38R?Pcb$z8f&+Ko!Q771kjmoNfjg*BVSks!mE+W#GiCOm@rPYJ&u44>EXEkL&abIt#L=I4->=&j)&nq_Y&WI0 zR3*+V*(iZPVU7Fpji$+SiaL7@%4r^t1ILJ+4KYg}41LH}VO@}&c0s1h_J z1htAs5XcD+e%~d)HMP77gCMNdT5pkFaNEP5{rw*U8~UE-)oP)dpKZ#ScAfdTCfmCM zs+EwH>KaGcC=9rG@gh=6=4RU*I(jR{xLvun67v@^i4!sb9(D(2?g)E`xQYw@bDCK$szF)ppIz7wD*9ocU z^ z_T~lhEMac(FhUp>mXC1usn5Ama`_lhrOBBm9wHuU&seL!>pSlbe*L#Toqg2-An9gU zPp~jkC+jDqql8+;C(kVNN1IOQGd8T=Jjd2kd+cnCoH62gNARgg2tyA~X-t~qdkQ5b z{eD7wu|l=xljjL&=kS{ugD9!1xi$nP#4^{e-c<;+bVQ#tF9j~-gzW}WTi2m23~^zp zRaFV6mHT#M{q$$PDF5EyeD^(mP<_+qKJ&@kFie3J2yYPCubL~N~}XL;oydpm11+jDGfUgpq|8`<8xK)o?TrP|=i#V4pW zIxMZ8;KI|7Ff(_6Acz?Bx3Si+eDD-XDNfwqmb0 zzTf%4`+%=L0Mt7nq&XXBwg@UA?YTO={+MdTXX|XA+FXQ^ig=I{wIW24GwdbI9%_@O z8N=-{wMIbRFUl!_z-Wk+BCPuKx?@I9=cI)uGsfxu<8F9Ql)7wXKp5v5UkD0o>5mPb z0$&L7vQLm{2L}#)iIp(F7!nT(bOD_P$$o$5GcyZsva8x<`jQQt$$!T z`isXIE31cyM_uamI@TH<{oF@bJ#^}-nD>5y0OcQu>-hh#Un9^Reowl_vQpAbu7ta= zCfR{fu0J5e1QevEW4_^Fgp!g*YnBV=P7{VcQ4~=W89`Vf9(Acy8$^{ljYhLHioKb& zOHUG28XP)yJ4xK<4<3Gi6F1($u)oX7p&L=kV;uKUO0jYI44doc@Pm-sU-?#M=MR$S zDMoAatN-Txzy0c0oQz*k2|(deZV(K2$8260P_29T$|K8i{B42tEwbv-?~XB9!O{&g zNrBa1jt47iv6Q>2qPEMX${Fb0U&hW~6%V;P64NefGum&Xsk#L>= zdgx8P>~iCD1GI5jL9OYcZ!*$sZKMRAqE`2iLhfGxC92&}Z_aYV;fh$ha*>0Fj`G@X z{T@6oU~By>^GiqBT0aXwtFy@I#~N;ZXPJ+x6xz_JJ9J;*d(>+Y!%^a3 zzROEoxae;8Nz-&|^D;BD?uKwZmWK0EEYI`4fw^GinwD>ahwkXC1rGmk$+duEANXK@-3@;oi43Larp zr9HDmceE{(lKjJ;`i(EU74~%?n)QIN<;fqdun}e~|9(I(atc^y3dPKR-{Jj@j8AFc^;UJjpo8oXCVRjN*j#jZFaB z%_`P9HK5MS{Pa*~sq5%kt$C)j7gO}$wVz)_2VQIXA-I0{zfM_za;{RoC-Ib%W^-MC zrpB#m+5{~70JyK&-C3vB=&-P`fG!Hg@qnVpdHVDdNa;}&h9Ios2O&XNVRqplXPO2$L-EamX=+nAj{Kp0gyeEc@H z*3T1<`pnE9V1Ds1o)=K9x7pe45s&(8?{ufEu%a;24)Vn0BS|vC(5Ksv$?}3MFWB1L zAWO%j$&le-mwtD%q?)p?ATW&t&vO2`zP|RuFQhy8F1HdWe^L&VeE{Y5s~@Q8>-`eH z5=9ZC!5&%{q-o63%5i#o8=O3KD@C5Nu((8)#*E_u7tcLL7}Yp@{0@{-D9Bk==84sD6TVZkKI8mieo{o{yqqn!o%0cHewzGK=sXV&7>uj!_quyu(R7Pby&Az7{gkEk6IR1{gR8TM0z5|9_@ zPRMxI&|M#*ZBCjMt^_a^gVSbD^NBPTB)N9_e-gq#k{6c#xNr>^pcW`1UrhxYt%V}9 zG#eiAP?INm-0u25*HCf-AcDh3Z=w?Ucz#Hl#28)Rc>$#y;=Y5x zmni~WUtfnFpu?TG=AOdyB~rK#*WGvOES~57OeyawQ?S%`Y|kvAb;0h=CWHPit8T5CYCS;nBr7^xAl8#3x<!}-o)?UE92lt38owUUUZ~RVC5(0xOlBGFl;1x$q?w_6Zpg5g z5mkK#n+~pC7=tIJyVbEofrrFB*uax`LXc+8EHv;XmB87771oUctDz$BBvM1Iu81m% zN?lQJdW4bMw-=%ivQw+o3#~Qv<{V*ErQVofVfhH_mrpalc$m|VKZxf?+6)Y{ZnQ7MvL!Ttg=(K7){nTRwVZ_qPF_u+GyD_`p=53K9u z#G^h-t0y>g4x%}6*9!hH=kkvvO*L1iojD2=?7&UFUgEk$g#%Bfh#4^smlm5V@SuE z&{yOL>`*%&fy|PO3M#YvH$&A$b}7$u1u*P8(UoRMGq5NgV34i0+P8K4fd2r+|x zqrv?>x*#2z7^>G5h8ZgE6a^UvZdxi`%qXMdm@|i6+KIyb-*fy26QA9hvU$lEyDzf2 z=~3~>v#6I+IP%*_U@X5S;?7{end^ju=;_abp1HumEvtyJ=1gOUp#ESgiV^7N^?RP^ z^MNF|TCK*wrw^*vS~8932!jhVsXrE_f28YnyzIR(ozj1M(_4)>zbAc1D%#sgu_i0& zTYE9U&NP2km3ofSl>PfBWEoik&JreE^?*~=zzhCToax+#F_WgSoR$s{=ilmoAdPl+ zX&`le@5j2XDd8iR+GG({ML;@W=tNEJfHK+^k^{4S_8Le;ACZ-VPM`Um4-9iayy%As8-W^5rv7y+iXjdp zEfuRf%xvlwsXOF1d@d5@ACxGE0!pA~$nanb>1ySY4X2^I)3C&lftta@*Gj56^)kyYj8o)rsl6&x?=Tva56n zALkoWk4S8 ze>u?xYud+Y70R7P=ExJeiRj=5`?Mo3t9_< z#PV`XYG^-}Yh2e*_h^(=MDg#YrDtI3ZvMD)txVUfxK02XdT-p@g-DnfrniPw=J~nZ z02H6!lN?#E$tNvuH)ecOMYxy`deXOu|5Cg0_Pu-0cC#R!E8Yu`3rBwk^c^p^iBgO6 zEeg|&-r9nfQQnXvSZwvaVpraJum$xRvJsy{%)3_{FU7U&ZOJ1J>X#x+R%RXl7Czk zim<@_ci#7B1GL-(?7O5s3=`ESC|JzzLYlv_ZNF1_zKt$8$;nBnTl)`cIw}2}V_;G} zh%f;P7$?=?sR%HM^Mn#D%?O)!&~U(RVvFq0OlJKUV$llE&QPhNg5l*^`@jrlTXrU^*d@DV1oBU1cK z0cthyM8GZ+e_dh`9_+tk@Bg#Mk+h*4Axz5w!2YuK0UH82UH##BCSCDWkOs?TkDf*b z7Ch6ff6MYWi^^k0^HoM`E~_u*Q}QPD^dZ2Nv353961zMIwfRzaKIEsemQx+8w`8u6b{D_Ayug(^e??pMR73RDBT; zah5!$&`wZQ;YAb8GYYiQ=TJbaAF#nf3eR^!G)mIV9UT+^5IH0S)YW<7iT*Km@1x2K zN`#OjDCsS?z~UJe0D&1IOx`X;ZtG^b=HVOmJHzv9iIBk8;n!+ShT_qmgNHB|_J;i! z63EX1w_%BFnDg@@NYI5$2u~?U24ryl4hnKQhPmSM_&yQ9>WyqyK(<0EH#`+wh`I%* zDtRig)TN^l1u7%8Tr64m#6%U_#WhDff@XyhgzsQGXE4RTH;)oABIYN zaQV@BNRC)2?Z?kKq&c1Yid7@%4buY_4Ge>%vkm8QyOmbgNXWI+Bd(t-&>@alij>Dm z#LuLjM1o0>$C)Ai*GTjoet^A7E9^1u>yahV#g!+-fvcpYB?L3{5QcVjwKF_1+0qX^ z=St}j&?AJ6`F@53p+W}gE$&r<%Q`tQTLDami||#)9me@%dbxLxj?v^0Y)2Q3N-tPE z`rFqH{_wTYDvjX5lh1YF@5{fk?nFohGMN#!uM+SO7DR&@_PBL5IPQ~nEtQnl13nHC zeD&?=3V;jVB~K_)lv!<6!9=pn`8jU1QPic=hXHr`C!a^dCC#w=*b%HIUbSx$NAuGk z$o>!!wTO4v_QplprtS~492i!D^(j?bV!1pP#+Sld4vl`Dup+Z;5j@ZU?~7t5XdLf)-6Ab5SF7AqZU@8Xe+|4!7P1c|0v9fx$`dgq(r^N07r8nh-Bh*saDk#GX)s`ZQ#MA%G zwF*EtP6OY!R8)4}-qys$v@yDwDY{*wKZ}4!DKz&gJ~Y;ohT!0mt!$ImV3pWb-o6?SARjR(QkrK2MBkem%|ESo8ELZa4JVVRt z)uuBeaa_|&uFR*a>Wzq)ONXO@!`+r7F1zOyUu`-k%?+kg#TnvI%#JtKA{ff(laDFO zcK$iVED;@$!FHs(#9H5%5cG!KBj|lLq4#uCWOaGunKw(fi$Urax_OnTb^(32q#V>v zQQ5_CLkLSMRiGx%A-e85Nd>8>gx0DA)NpER-NOTW6dHt8nwBiB&I{cHNiX(ZDT++e zjb89Y-zMBY3FCX0O`)szVE=KGr^(Z_<|20nKOXUJFc^FdYC0_h{rVlmL9gStB&6Z>;eqhCkN1=h^f~ zKmQst@=w+u{1@1bipX-Qtz$RhN_S@;y`Mf-q-QsmVQA^M53N=*bcmABz?rBeuLc_e zM*Hr(l}Cwrw?DA?vOb!>r2gP#8a*L3m`}+rze68^#w5TA>yg0s3(711nP&)xe?cG1 zsakqte3Vnk2?&KJih7esUFv+VVb-TpjPgOuxNg55jAL4G9>x`P9<<2gGI-1@iZ@r_c3i4JMf3bp z1JP%1BBNoOH5`#4m0YYb6^qaWXU7lO3^hmVYj8#eo>Z>V`CV6+NRwV_XW8Gy%YieQu;9hP+C^`J}C1l$VWv?NQK`ypzFrN*aFYza<_$Mw~QK24oadu zzNZfU7ZWS-z-CQ*1U0>NBgx6}MGA)N&547#O@As%!u;99e1;)KCC_TWUG(Q8#^;2Q z15d?K2|ghF#eD^Nr3-VOUvmH@=Rw=cZe&YK+K!%@mDr@IVw#U0VsVkfXx88UFM(QI zvMzw4RJ~!URZ<*>!7~a@DjN$vTI^NUL=Gk3dyJvZ-Ce;koVD2vu6cxbDzE;Z1+I^$ z)Ly*Abl07+b~<5FeoGU9c&8u=jI+GYhalMy&cosB&lRJ$>Z7r-J649noMeVpU7xUA;(*gJK=&;iiG&SN9u(aKVP&;h zM5ZP-pd7pJl};#+=U!R=M-9+b%w9XVjn@fIQYGZ@%8y+h_n-HiKmiy%Wj3?*#;q0< z#N?Ky?Nh_h&kYThO;uV1Qz><~Bqv7A=vTv)JgAef|zwq{F|B#A9ua$Cxt zIil@7=H5+;aTOr?ejc!sbQcERXZ;+F&?>r}ANp-sL;)lEGY#$Rd&kE?T8wt{HL`!6 zZ4<-$ZEnSK*4FF*W210HE!_HPL~{FSN~sycnB+MLWc96x*4aGuR(C!*U{T(B-^I5J zZ{?U{2`423{GFc-0Y=M0t{m7I-Ih3K0|!tawMl7S)rD-Y(%cev$|A3<^*zCXkRnpK zb+!JnU7KiG$39m+w#URDBG0%0!>iAoIF(ASdihf;R60`{zS?Py0y6>r$PU>fh3=*?dUo~wK&^3QFXl<^f-*W} zNmJA$_p!h2!4tMjp<BYWAz z0F7V-$^2o9kv^uCDFPMaxYn(cbsdkrY31LydORDpl)sh?KD2yFE4W5XEP z`6ErLJ0BL%+OuJ51d0~JH8meKi>bOTUUc7ssWs?s!Vja|KkzAfb;69I+hjNR1eCJB zNq02xMcixIISjcZ=ygeYd4+8j)cgD}S0B4fHwR!!JT!e5P>4m=7kO;9SYbYKj7^$L zwnE=+ZV@RJpdxfg5C2*|8pXdPAYE{Wv%kVdim%BK?G4oU z+^3zaNWAy&5iz;5S4W(hMx8&SR_ox4Rj3}hoNE+_6R;MFMPTwrHsqJaZRGNHiOA=# zs889BO3~+#?M1*f_;p)31m$p8X6rrI>DfIE48&jj;j=q7UWsQ8}P@w|`FSCyWp2C%tf z^DEjk;E5aV2HW`0fZdSP;2PCj)!iz*)*LG+)82%qcuBg1+23yfszD`)j>F6EuLZ{C4o zNVfSS*!{K0z0;t1a1N^(OpKilc$$+k8)QU-T%C6kP_03mR#p4}WIFdNIRL_%Gix;F zC6^ek6l16gXm^3)iN{I{EbKl=AdW6<6?68i`7zm$l1cNN`N?z1o@6)zcsIuybkqGn zLkIvMp9fLcN==YfC*fvJN&LhM&8M`PK=`jfCRcy2fT9wvST1C#I^gT#xKj~1p-s3^ ze<)PV-kk?RUK2XHfiE=Qszpd5@PMd{Th%(IhPsW1n&xTiSEybZ5!8@?MLyp=Y=0Z9 zPcHc+lL*$|d#|3AtP884(}7bEsDJpmohrqG$P5`&4`nU?t#}Dem#1`_7&uvW%m&kS zlo)gT`Yz{=X@Teb@lzBm;A20EywiJTe~M_J7nXW4HagOD0jEq018l{mfUSQh5%PY( zTjPvjB5MuFsfuY7h^aL6g+6?pm?AUx{KSm;ORJPjT@LXKFp7OjBnbcT74lb;As`u2VUUOf zB1q+`IZcrl55r&x8@Hb}ZxjJggy>FpKwaSkU+5;JrcX=}-k(F`S95QSyT1#Pm9e1RWs z^HeoqoLSqw(NEG2Wi24}p`$0Ti#tZLcU=9ULP*0e@O8S28d@yZ!7rC6;B-_06(N2( z$qKT}D<3Fv4oyKbP|%x3f)U2+b`iRH@VuQmsIy==>OTms+o6Vwbs-3~-T99I)sg{Poj_ZJ7$w6q zuGe;l0!A*GKeHAy5#980$nPp}HpY~q&3Qad2E4d5C3gL^L7@%tT#(7_KqXhw0IEYe zI5qtLrqQ8I^TfqefAyb>@4N<*^^U0{(2TA2xLov%K2`($($se{tCr$QbEp!-KGma_ zAy}c|{x3<-ZK?)!{+)jsMmB_;nRYu_xir_cOr{Z0pI^tcwz_#e+5Ideiu|F^|yt_Xgs~i?r#W-%?LPnlFUSUhZRIOh(0_E@a zqp4GC-s>O+zQphC@wrX{)FF$>JY#vnhrl4&Wb^7>df0P2yUuH}&l@*bs8Wy9Kws!( z;?QZAcQV7;LSRD6l5rfpQ-EM9bc02eQU~Vam@&=GB&&8C z+L98FuXc{wXr{S}a$-L{LldE?;CvjvbmuQ=z9boQu`OgqlSnr06?c>*!glAAz8(zm zeKg%M+y`)%fMIZk5^Z4mlLC+(*mZ=+M>mf@sHtX^ng7(rm$$SUP>iGaCy@El+jmk< zE5C=}gZuXJFQ1yTpp_DXO-?wYHQGN`ZfW*_zmAu=H-oKy28(DzAhgUkas#}ZjB^>X ztFB`nig06(HjQ|t8g*ZVV-M{^6<>{|G+WW-S`LNIVD2=@VaNTU^&bg${{L%RwRnd! zeHB!=u7X^rj#w=5nq}6{bEnV#4*kiqD_$wUh?|FzAARA{Ljfh>qibk%@sH;}+_)c? z{$p57u97o1gqP+xR8c6ZA;q%XA*_IbAxk}Yytq0{EA&bZ4U}Gv?_;-sDv$CMmU3X= zMM(0$48fiGOJNf$Byq;O+Y)NkP*3J!_3!r8w3STUwW}v->HS9v4W|1`S@EAKeZ~et z0fAw+-ipc8#k$J5xZb(cbOD&YAHO$q9JZb@wmxFR0xn+vYiO>Fm{&Kn*h$`C*!2l`m%*9$_Bq@#&i`oDzJbBN?!dWph5QY;uBcwS$fZ9&I01pTVFY=5BiE;78E2MH`Ln+e5S4oB`+B7{PF)z5SmB zA$t=!`Kmw@rlvHROoGsg@Phl3`G~A*Z3(LaE{3YQlkLNB2fne1O~L4x zY0R9FkL?}1_zyih1zy`SX<;=ph^2Q~lx(o-hRbr-38j_eE+(;^3U;{K>cS%d+LQG( zlgq=wc%r&B{UH_jP5W9uNUe<2Xfh_~nhL{TL{cxsh7EYP?!052D%67NXT!hcYGdyt zXtls-JpuO*CJvoC!t+eL;CiPsRcx0rgtkBp5R3;pgH zyIoma{~vp4J%@5Q(gIqfFsuR^*dmh_;0(~TRs=~&7N<*eq|8G zos+bzq$tre+ZMq&W2%D9h+yMMvzv@d8$d`7 z*>^+3nKo-RK=ZXj#yIQ$bgSuUTJPht_I*0FPXreb|+wRZP9}QkHPSF4W+ti1NU$wFoeeu$rTyiLi3dYG5&41s?%$V+D zz6_X%m#AmDKOtwjLCFiK#m{(QZL5oA+X69P=FEWB@NIpJA)+a#wt58kHscElNFi8` zlmJXb{5lvTC2Hg=?Y2V5jiLQe?`+ei&-nCyX;4Jab5auUuBEbR6`xda zdg=-gJbAeVjBM}VHD@Df=-@rLo!55WkiMa~2R{8pr$6~mtQbhb??QW-K~v!o^>}^dPzbz+bzOt#nsbt2f%To8 z)IH}x@3T$;A6?t;yW8N6)8)^b=PsI;Qba&R6-b)o*u91Gt%FbsD$W)lYY%m)Yc;%? zfpi-nuEuvev!yrob_f*DZcoZS4wgs(2K+uGuq%%sEh^5}z`$(nVWq8yl`j~-s%(zm z)h3WML37bcJho&Qya25g%%~Ei^J~H+curc?@RsVLB~iXUrH@6D(5@EMw0@khRykZ` zTy8@76xb|K)mQFZyrN~sA>Xb%$`%KYr?cD!eOz8|%V2shxr_O~x*KCb+|4Q_#~n~= z+17tsX2kok%e~fQPG(}IIgDZ6paz}ZWpwRXw77s4#?{8k^qd+xJbno&@H@X)9;Kr< zxSmMI&Uy##&~2MU><=g0$9r{3a%IK6op0ZD^^`QV-Dgn(irZdin})q~g=eY%cym?c z-oFi~+WAnMNhaI+`ekGx7H5k0Yrh7dvV4m2B z^Im-gNcPf{;J{cC$cp;$aC%Q{@MB%vZk%tle3>#lSZ}d_-m61W8L)ft%Ue{C)ZVEUg*lvsNTQ~Eo6*VjV2y-TN{j*4Zw%g&jg z^XVY4e)sNSul84fh$pzrPq)dmUs~3W1wcc9jzaVp?5)X0azq37odUPf5?YAfX3;SE z+GonDYX%c8nJaH41Z60r0ROl+qmLkrjLy|A8#)FPHiUC)qzR%LHEDE%TY@)|Pwr2& z3!7b{$08p2c4s0MPkxt^tl-2;rGi~h+x%E4z3##k$r*v08 z-{`2D(vIK5n;AacUy7jX;m-><1gKm4?B0eksN0ELF&gACMKO?yAv%eU?W!HA%IdKj zet50+q>!OkP@&A}Tp&g6sx@A(VNGjFmQ&EzVMlKoMg%8g%TGYZdiu&{_kUGeefQ8T zM&6-0lM0Y_V%u)o^33{r@oKK5yj+vsVVb_#C0kNFjkqw{{Q3eQXkn5Ts&US5YFOuL^i%IE4oxwyfUiho}b?UO!p(#MX3 zeC*rat7>`<5$+}MAqqD6uV$;~aVJmGl}?_ktHg2ksF69GsH8LGEvQq=?lTKU*59gpMaM~CN9RgQSrO$|6HsnH*K?oJV_8MRHMG`e9b0D5Oc`$6y#Fn&DiYFG zHsy7Zn~Mb>eys`eECmZ427CX=?oC%gF!**ODoL)BU8M^<;mI&DscCp7BK4>wKkT}p z?fOyT9<@!R&jFwnBY#Fs#oYL)(7qd6?#_XTL5Qwy-*~~gz&peu1{sy^SRsYg&2EUM zSlqLjrLNJ}|BW+3&Ew4{E&f;G&z7!Bhl(FH+zo{;gAPd!D$L^A8mNd}>(I3&M%t;6_kWBJ&hJTmKCAynnQ_h~X(!)6nWBD2wBX@X( z-hR#RVQidPIOb#ON=%ZI=YWi9fAuh{H%}I;yS_4TFYIqrSGQ<^Qzqo{ zhRj)&=+*h?DDt|4|E!DdZ*diTOfO_qfD(57wL+I>^W&5W+2Q&BGI17dAJl%uzI9ozCvONE=dg?e@_yQeaIu6yXD zK?nN>K9Ruat0`RIaf9m(JVbi~X+y?F8rsJ3UY$vb=Sd*SH3-LGN=&ilwBDZ1 zCopwiEQOudbnd@IOpDw#2FO_e$hxjmwD*KIuBtAR&qM#5snx&|Xv{Ej5fU+OPD8dA zY^S4}F~jXIP&~(S!{*xEDLKA!c{TmM=HGbyCnHABF1(Ym>b}fkHsx^D-vz1w7HR(YPD~9?Ebdt}!&c`YA13 zsE5QhlxP8``@`ATVrjHE6>3&bA^E`n#7ksg-ilRZe4!QH@7$p4bu&o8pm!m33z#Barp@l-IH%#= zt?-<6$q$hUrkb)iL&`v|%m&Erq+eM-Cdb6Bkn39lG9nJCV$FDuy3QZ3A=j9%rSn2x zM@K{=mxe?~*Eq2B+to)r8K_yi=XCnhHw`za_%PVNz{pzjFf4sK_P3D-QI<{Vmt51< zENpL5T_{b1A{9g^EKe5NM)_iuk_rN9xE*!x7`G2J;NN$Tavn_`1p>NbIJV8a&_cF& zG0m&Beu83JITVE*B}8d-XH7I5otZUN=64K{nV2;oLay)I*d}LA zrh#E*!FmiNoMFC@#`#7}UWyRw8`f7E+m)%P5!^{&)6z>wG-2HoUHcr9k;3M};qCcw zgxL8(%OjpOCE9Wq6TxYJb@@?fXVdMNesr!SKMGPzUG*%fJXX@(RvDT;%9Olrf7RYz zqh|X}&nBx}Ne8#_k*R&3>9;ki)Y22eR-t}Cm>~Lwku`z^EAj-o|4zdIrNrelxijq#R%^_FtqF0JY4z3Gpe=N^kg8hk)~Xwb}8 zV!Nu6wFm1(|8SgzGm-A&V7}YlM7*>gtW>0jT>7LCw}Bh#{S~NSWILqd;?4`Xm{3JQ zIHQPO>}1=WFglDj_dm>P>YTK^soH7q@LuaGJADzJAY=p6ib5Hbdg~t^Yy5YY44ap@*aHuWdhcv+4u zJuC#43r)S07_}u_UVaTcnC`hhL;Lj42!0vcfLi`YoBz4vLn=-{UXs6Av6`X0In{X1 znqhD3QD>u_o~eb@XHYf9E!kZj8^DBRWZ>F`0>29 ze6z;;i6kVNzrFb_w!%BGw~9506QbS8a6{{(zJj!bjvz|yvM9mWiutgfmImp}e-M%8 zJ}5(`Y{}VX57oS%?O>(O>~nqV^@>b>9u&28U)`c*qz<*yoe2LnFO)8adbc4Hw2IU&*;f2q!M>A}^#&IB2ulhz08J zc^6(<=6y*b3q00lLHI{D_4P(R1ciQcH_v&OI1c$zD^!Ni-3MGBwQ zc)Nxq`aKP@cd)9w%W;mE>&Z+3WKKJ98=O(R+VOdo2Y#yQu$x(i74TlyH+p_fm`Vuj zbj$BsopzkrmM5?cV@5Th9#xlYf+(H1_W7)UM++4q1LD#&&c5LCx`QDL7;&3FI^Qf} z=R);PU?reSS{pgV_FzTL>7~yYmy6k#Qqko3Fjd*UFfjAp{kKqn=L_3SiIZG6O8_&D z!X2qcxT<3x@L-ll5=g~!h2cM)g$D~7fx!^IHLJ4Z*7fs@mar-LY`Q5El(7{DK2smh+fJ+ot(c-Wem!?(KOXO}$v#nn zKJYJNa-jhJFFnFH&(k8@nmANM6zM&tkxhf?mn2 zw*;o_uXf8cZi*KIJN7jwe}9#BquGt z!S1GcD?2MTVUUl@qOnJ|xyEqjFNw=ynY-oByS&V;r*|9F3iS{h*O7o}wdI)gOt^bZ|aEXOw%iihlGB{K0~AiIUnr~3uaMA7n8h|6_C%%I!QMz z*}gl|n34#*3Q&gsG$Tg+`;Gr0s%|P%08R1v9SS}ZQ^`_`2b#Gqa(fT*fRy+@AL_#J&#TW0L1lVYRhxyb%EiNqgtr1rMy zu*90T3yDC4=o>eu1uFhOC!5?LYup=zdC?%^?%PP-PVtGUsqa6Y)2=^KRf4X{Q;ep& zUbxF}+UI;bJ49ORx)$=+NRsVo5RK{@Qq`(_AkwELF%kE6kask+BscJZbHDK-q8K6@ zt8Pmt)~+G6lXH#JOh%kE{X1mI%3?7xPA}#IqD>3Mwn{6chNg)aXNhGW5mURzRi{s` zGzJn;PP6ZURLS>ew_&%QWqcqgB+uVa67jZ7NjV`V z-AgCiDYc&_nu$?%E|%>^PD2}uU>{cb8+M4?yasX~Lg1wtsD#XyIA~v{I}7~&0fw?O z6tGipgL=-JlQuBOscqG5<;2SHO+?fuGUWIgLr-7U>P?ZuSBg{1w(NfDZnN9nCAf1F z;&c8VkGztwOHo@We0cSlA<3uHv4qB zUjoBvXUSL;Ooow%2c8DDR*bqLl=${r)wYD1`NCQCt}w}kD`#^bU=gag*7I-UYRsj&~w+(t*kDq)XJH3i8_o5^XGLIS2Ms-tKyq_&4pG0e)QC1X3 ztT&*Fu$$4d}-6NeacB>BW;*=$YK_T;>f`V1W*)X8uN;cl-^R9BXtlzZJKYJV<$7o zA<7|^ek=Wb7VMIGNV#6mq@Y#z-LjZI^T*XjV4myLs_2wkUQ)yRRYz_0&hdT5w6(O` z@z(nUf6qPRcKvZR>qnoqW6(*05eNB9+wv(V_I+1C7umY6oLcxHz|GBL-Z=Fr0Z01V zA$}-j^h9Z_>4ZoTZ1eEU1C8ETvAKt6s8sBG4ULXa4R>G2&^S-@o@nllG&~cYlX0D0 z%mQ)}m%E7>y)t=|#L$-;SV{zk&tMY+m<>qcY>HDNQ)U0eBNx@ll&BQ7OV@cn;0;J{cI%MtV zmcL{LhW-nn!N!Czwx^|rtxu(1M0d&-NLI>U|Kr() zV@(~{x$&Hs&JMBYaNf|wLTs(=ZIiWqZP=eKTv^2!_v~w9qY<+~-wYV|okKL(jwaaK z)|;V$kTivtGp(gSO*(xc}(lLPO}VGNkSD# z8R9O9We({=>1F0M4p+}pADJ#g-@do4E|qL=>STtNz&}wIoQ`vSHB0({;KNj+Z>4y9 zsK4@8k!S8CD}m?aE<@(}&`Ch+jzt0l{j}_MCbe>IsD3y5Y$4&WrT~7>hJMZ9Ra72) z0xuzjhggc$NwHV|M>_u2t)eI9j>1InP;} z6kA0%w@P%sn zO44iF`Hp1q4y#iW?`w`BohOC`24s>Z@bXaqO8DmCbVz{|uvGokzyHgb*?!dVFAGjK zWz`xua<)@@0y$@7u7IL5loHhn*>IC^X`F^<%7L?@1x1)llkiNk&@US6mS0f{H2=I7 z)S<-060?=Ss-c3Fdc}!;?q#xE^OFPnaY?XLDK&=ZzfpUO>zfCaJin+&D#t3CdDs4I>3Jo(@HtTRA5%l@ zQ@V-eRe2w1R+Nn6gbx-&^ql(kBVw>w#bwBpGfgL@F5s;tEArC5B;c;)9gwXyuV{Zy z`loK=$0X|Be8wP$jXO6%Bd@RDf2*JEU(Eqn2$4L7Lg>o&+&YcKd3wZO)_6BMQF?AW zg2D?Pk4*-a#*^dy8`PwHEJ!!IBzFvq11(XDXrHK%C7GDBr3zLM=p~&U2Oc@-JgelC zLAy%$;)n=pIKe0=gVo&D3uEw-m{usw`vpJr`*vo0e&-Pm+?2+o)a`&S2n5=f$WwVz z3aMn`jr|`^!$R+)@`Skbd`Dq=S6*~`TAXg;bQuja=$llX{*$(4a468ln2n|;>V~y~ ztxAKX6Yma_WPqODtu0r(PKqYqcYR6v57Xwr0EGxvotVdXop7Xy;4BcxF}%Y_-nn<3(37l@k*jbUV24{hmrd|c_c{%w<~9y~}dQXp-*iPc{W3jLRr zLPJ|l4@bbqODN_?m0~V0wvUrFlo7G|FKu%A%NjNNDm}~Bm9vL}u8egX0h@$#*@@2mu<_h+LFhe`i|*&F-vS>vz6d;fFG(`aTT;vU z_4Pk98fa%`xqtdL0lCD+OME~#>p^h^ark{s+^QEG!990lLL6=Anp&|rFL(Xa@KG(2 z^btie31>l|2XI3_-D{J+liyB8x)c%sFmN74s+*Y$R?5afNPjg*Cyx@s4Dri=eSqY|W?Rl?+2O9y-e6jFiS4 zG_;HGACua|Sm!L!AtFg+XCeTA_;et7b;^>CTapWe*esRY9lApj`o)_bMfJ$#l?5YJ z-h1%mWh3u%dn3ijd)-bLK=w6HueG$NW(2tnr(M7`KQ_|^C-%ySKrTDuca&KcyOBti zMB9eW@O1s&j4PFs_i$ERp{<4($KF4?PA#HgW!49h~I7?tgT8@!7bG zHm}S)rC#C4!`I&6h+>`{a=3+1L_BU?$v;|3_)tYiE2t%3J`$0|i!sAF zGCtfS3Mk=l6aK>T?n_D_F$9KdqJF{6rUbfR$8vhdi**t9*72V`B3et;em$*Tt#z0_ zIsJ7@cKoCBL#f6j*RE$bq-*%I--AhnYemVo-Bp^oZBDG}3X)8JXR#J(IZ@=@?;y;& z9qn^fmz8K@hGrlE5>F^I8-o_h;?05<&q7;kHc8M3`ilk|%}Zy-l}q&RF_3A@mZ!{TGi`7W-B0L8tRGx< z)g8)OSBNKeU5-Pe0s^(OQ;HOIhFCT;wX>0_LBR;W(txK{;sf&(J&Nb$TErtU&knOF z_!<&Jf5&dLzehrzsR~c|(i{K%t9>^Lww0Ch$qdCs+j&e2t1=l_6;t{he8;&h^d921 z{o-7Fg5Tc$_U!pwqrGodq(7iqPZwR=$(8V0ZpH5M#@3(z>oJS9@8tGl#dDW?#~|Mz zQ>KI~D!#h!;DC33kj1*nU3^KDZ;Fz_|C2Ar!N^A?pH#NB5X}qD-f=LVpCktkWuAfi zdB6|j;gj!qcT?2saSDNy-&a(O<2MJt1Om3uczwHkkm{7fxBf|2|Ma?$CVke|O-piw$8zW-A_CLo5c zavq55$ZzT=-hK*vsCwNFJDZ}p1&HBD@%g{7Ddz~#T!Z_nz?87ymFq5r71-69#*|&@}FAb4z%r}MR-Vp2eBu$ zPO#SB2#EBJY9tV0Uv>@j?7M%B~Nz38%y#F1;j0 zSV1_m8%en3J?j^&Xa=qTBnBt~(l0~>ibTGXvY}t1wFpAhpvwVSoZ)lMAF0s&bVDHn zOu0N;S(s>9S@ZLvp+(tBzB)0%#C|a zh>ceP{dwN)zm)9Z;%U2yln_x`Mt7$?Ts4mEZ-&K7WB6^vRFtSvuysQLE7O46i$$U? z&({pMjj{Xw<-hEDMhg;ai&%iY*<*z9$gw(R{{w0Jr7htk4xo7__vsAT9Q=2d+J4=LPmJT znLyNIu8cu9Ws_l>0FM3`nOGo}bKhinF4wztHX3siI1*$2>8(h z43qG+_4X`g$bKP;DXPH0X0X;E6v#M(9Gh6CN%U_{Rs*UBx1ek}a+{5~MVIrm9Ue0h zE8DHX28IfqvPqiiXEOWu{DU)Ss2v@lQDn;UKDZE?34M=nDBOsGPzM)tl6X}GI%X3$ z6e8pdU|d@p14j-X-$D+cUewiAYGhQlB45j?{&f(ypI=G3FlUfyjvisWP5f=$OczR9>T9=hU7?IB>sJxA$~8IK|^;wCB|qw^tHC`gV5wIWO}uwBsRzP6i^f;IeSJ67f4@ zlJh}NQ}|BzsI59Dg9En`IO{Q^w||pl_B$u%-fR0cBB4xUYJd7UFkp)l0MO|%`JmAK z+l7%NQ7|xMIvPdA7b^P=McR(sT8ey4j8~r?*tBYP#j%gAeW=+@0X= zIuIa8u;4DiU4sXQ;4(;p26qeY4#C~s{m%3LgFEZ2HJ?v+pWaoqrRbs1m>IoS84V)M zhF3BP?#3teS23N5E65%~BPS8zex!*tXmB7VT;^FJ5q3Q~;f)QSD3A{ZN9nbjmzFv6 zw;5QA1H)bFkq2r(GT0T`zy;n|p>7q%uC1hUk!?qh9%QP6bJp>19(!l2E!Ga+bH`LGf=8|UssOjJiBh|8b48pvG5cDhbQa|$c_fMoRrQN zRc+`ljKnf~c9Aq!W77IAW&C0NpW$1kqd!gfg5%$M{!Y}Y_A|0UycP)}x%|b5zGh^e zBl99|nNii)f?6MrkB4$31BN(?9Xz>5F%=GWcdoT*hTz}WaDO&VLe*jhRdLQ2Ct1o;QhhFlPoxd>|3%z?ofymP-mFlvl30B_-nS7C z6_9w38~)>?zu7`unLoZRcTo((--%xR$T8B5vZ?ppE^BXm7liB}<#yaw4qrE`iM}Ox z+`DX^RI{AdD>tQ42wqIyR+>dit`+L6J}|d{?Pu>-ZXt$7Z~ap7ouKC%1XKY3m-l}a zMO?3Tq7xiqbD?M-KqT%QlIqr>lU%{YxRnFyWnteZ z0ZK9Fdq1CmuTGQf?XSPG@5Ov~$Q7;FGQSOl=aY}JYgfDH;fyfzj*h0NkCtp}EWdIVZme7&C8dN7J)Goi#1A-kOT+7mGu;%FX&XBM|VQx??ycm?_=z39UD#K5dlu; zNfaaIBDSaE^oI;zDItF^TF9N|b5>_U!$+F}VE3Uc$r?I~ifG%_x!Zj$4`pMjzR|6!?tAn=un4j9{7-%mCb+?~L z998+=9@7j$lpEky{iHlE&e#iUeL#Tf*RA86nH5{t%ZX20HDs8()3Dl1=%ix)1{34s zPin$9u@fAMo%rzGnz^sTepg{%qu$;k0)`q$9ZOCv)`8RxpFjU}m>qUC+Q{<1brki` zdBwv605-yH+5848*}kmSQiaV7XiuV`eGo_vf8CG3!nYM|LBaS{&(ZM2Rre)Rvk+K> z)+{x|H%{{1%??n&V-Otz?%E{%CdM_~y%GawZO35RbXM&4Jy}+#A4*DpT%y4+Z2z-D zzyb!k4a>G;N!VH^M=|u(pD%{fsId+?zKm#!xlHUBiupiT1>To@?nvK!KhQLGmdHa% z%b>ZY6_0OSFlbj%WC{SJL0;!~5Rbts*ZO%uiYh@^MhWbV?e#Ol30}RdI6r^Bdmp+E zxX^JJvRot&o&x~hlbY0 znuunS=%?(o5{8Jo=fZXcRda;P&YQO>?wwUdm5?9PCVV$@WZK{t&R_3@YV#=$)Lwh< zf3eTHwrw1-E@X)nAub60twKsC{Y`6~OA%UpHbbmox2jnd=JZjDCK(y8uKi0e;R1;Q z`UDqrMj>%9QLeZu`gz_I3Jhp5S$uKD7z9|1>8{CHzN!|0i#8vErv;|Sc5@#zd(%jI zl!QF?;iF_@xEs{sV~XiM{uA-Jd)~x1-fbWA1p($4^H|_-DK#oq`pyTwL z)*ng|ijlH2PVcs{scb37U}iE<@Lrs~t(evF))dspq=sS%`~=tO(yKRKA?A5CIds36 z3X%#jENbPBw(Ac8p+P4wOFl}{|GecQI^)lASbWH@p@T_^1kmvT3_RvU+pv{soDSo2cwb$z z7#g-9&xekWW0*1x!j zlwB{zmWH7MZ$kU9d{v$WYKzh(@G9WZPEN2`=YlO8(v)HS_!WLt$o@=sKvj_z1%}O!GB`Pa)51kU%0`#iQv(f_*Dc!w;{s2 zJ*x67$g`GPo~XOQFi@R`bDKp93`7>j7kC)c;9E@O{a&bka0xprT3#PVO9nrTdvxIV z?b`;t8lg7dSiav~dyH+AYCW-N> zfPh5|DMek~N!E_ab{spazETd_xq6IGPy8=u&f|e28=-#a3D6B3^n&LjwxK?kfqhY6=y~^ zX)aw*bXwurv#^}Jf-5pWs-Tqi(7`H^rSB$`qDqs5{0js@`%p)WdBqhXwPWh5avz0oeve|zZ^U7f(2vT{5LFuc!wUTn~tfF=b0 z!HD~BGY33AK_Scw)=RR%NuOuprV0sW=-g4OCS$nv3GhTI1t=;#Jt*{;uvFT>fgv#_ zPCZ=%v{FXXNRU;M-GIMj%B#r>AcsovSk`&qcHk3mtE(13AL(TPIuG^y7#V_v_n3QiX4Q`&A;7 z%Z5#zwZFNmSz0;xK4u!}RZbfGlVIBIRx+0$QaZZ2+bfwRG?gckWDfJL54EWe(yK>- zjJDhSE$yQOPOdM6^+C9j!GlGHbuSkmN0qPw(5j9jK(NRBSxD^Ja_3!$P0%T__2?He_}6u zT`f?&XE12MWeq?Hk-!2=#E2L3WCbvbj!8A!Tuo*;qj546W4T)V433%kDr|*{?@@?O z`pG(58Rp0zxPV{EUy$zMC^+j{XkNa$7UtdTt!a5bNk0*zA}e;(?)kLndALO;Rf6Ol zU3JJ{k$ZSH>etZOc=7Iz%k?gre6`Wo`TqCs)OOMv>MOt3)#1!lWC)GrJ(+<2eoC5y zaO#A|LBfn>%U>NJ9?Nkb)2lQo*+Qb1Xu z9I(vrT{kD#b%=k6Fn4XZQw8D)D9oG;QQJkx(ld=D+t;LrU5%H>p{cOET1zsnC5)ol z{}_wL=g-phe?m*{*JC?)GsS`3C$kJ!edICm>zs|-JiMQbjy)Y zvHu724K%%@NE~WUmorby&0Xtx6^T@wBl7X~RR^x?nhd_*vSV`j(@RJkhU|zrk!@GT zW6fBsqFOUnj}j-yyn}*Cv({C15=blD4TAq?g(N;8=!%FFM<|5>fc(V7!%=>bm*_7b zv9~15|lum9+D8y=M8~ghrq#5~$5|J3TS?}D; z?)zu?I6o{tj6#?8z1nQ~-}#FFfLUuid2W_~w=b8lzl~l8ZuG`~i(T2~_D~a98%^Ot zYT~%omf*yOW+~bL?JyZu=YoZxjmZ){nzDn-gzfkd6d7N%;o{89AO=b=#37W5R%2tS zxiLT-J5i9Dh;m}B*EPPITNQ6qyPnh#@X?e4ao)cBAQJAsJaW)F4-PzF07C>I$>9C8 zP^kAsai_kxKfd>#MBXxr^EMT#m80vkEAfd1N(Z9?e$}`59|WCKv|jyTZN(%byEZ}x zOkCGLzFd=||K7cS7z2iaXF~=-f^Nch`S9R=lm?E%RtEQ5WOEiEHbG1{ift%Y5nt_B zSw>05{GxDsjiT){?;>1bs+d(mDkp^a0KQ;t#C39bjTJO_Nm>|{%|^+cYqp{)0759M zxy440oFx*)AYR0MOiWz-d(-{);^olB?jO(>pGSNz3)43meZITaS3ePHAW4sl=_VQ$ z|AaTFju`lY_!XBL__Op=Dpet9*M;oS7be?Kr1aAW!_ExyQOz96<|4H$=+8a}zy}IW zi%8wR-51me$6vEGp~T7}NRhDjgjb~H*A9$c7IKI)CCM=*MQmFbFR?Xb1>_5jv{3R?N<6{%=@GM3$dRE;a;Awr#)009&@#-NT)OeFaZY&>z7VEEk~nr+wT zh664Nh}&0v*4LiD{yN_HH}<)=yO9t#Q0r&@d?F~h;E?1>eKnpEW(GnJU)e`Vs~!uf z_S8oe#YcrC_tfh4$p1#d{w5~fj|Gi)?C3_~*0JG^JN@w6)!B1|>Dc%{6M1f!3R=79 zLOnhdIe_{BFHX=562Xu0&x4=mo*mmZneLLRK}AJUSsIE!kPKB*wTYGo?J&ek%8YGH zVi=fun&0Xuax{l+GuNU}sEI*0p=x4x!ejHT_x<2>y!XCWH^FLdhB8X7_OU#|f}6uP zbeM~fRu`Ht>#q>n^v)=PHn2cR&f@#vJ@$pFzFMcqej^!X{V+9D`cKTYKE7%ESuY*( zZh#Zl&~siBf*A-3uF!9^Q6$2YI@~PT@t(>ir=hL<&EvU)M+$cc!R1C(akBVJj#74~ zU{aJ1XKnH7e!`!Q&l5gSDcH(n4=brOEUlFo(uFx%?6`2pa)~*6!Q!y-Hz9mIQC43( zyfgwPHIwccRT6!9OWun#6lazh+k}#eCA>^Cy6Iu~OX^61nHVyv#G+~mt$>P8+&FQwcxgEcwa$U6yl7aQ=zk#x>HLig`fWqWg@#@htg*5XGjnuaGWIwTGL6?1G=w0u z+zCJEevaIVZ7zUAh!uzX98cogIA2=#@0S=nt5NqJZoPQHkz5TaVURtMp*VCX6pZZK zGGl>8Xyg>3!@u;?ZGi4RPe6Qttp$g60zKFlo9k5`#agf`@IK{5{1kmxmcZz z+onYhCBF>Nl%F<-^B#P^Z2Vz}+DiPy%VUJ|vE>^#dB;7oZmk2!^yeg)(bYo>n&hG1ei0>R7ZoGR!645*U2*T4lyhFV@I_7l`My&-wE6MkUFY>oKyl z$y^_sbzwqP?P3 zJ(h{R914!oHy%@U5G{OuawKB@DaV044G@XC17`fV)1%$huInH<&|DcyuX-)C-c%ua2Hf~cT89%G7OU0WJ(`!-)Q_< zT0UBcMVzusX+^cW#GpfL#q(N(3?#fzBUBK#t$_KYSBBG%{Pn9ryjuK3Fj)4LQo8Jg zY^+Je?mptc$Rq#X^@f==6S4}6k!-%G(4Df@m(LgV^BE&mp4q%YKB>ZQ8~jsCBH#a{ zb>Hk<{{32*EmAk-4*2kTB zJ`JdRQ-nYUzRB7;G4{fRwKalSD%o4gD&sYN zZ+kQt)g_2@+<$o)Mtb}2s)GWSv0|evNkPq*TyNm}6EOwvKjLG)6LF7qP%^mMK4R^v z0n`8CQl#;f(I18F4J_(aZ*D)>vPN1$g`5(lAQ^rXJs5K!XCw{b$lnRzX(1+Ky5dao%@b z{nMU`7-cpV5Dpz4yNoS~nxbu=r_#%o;){p9PRCM<-Mt^CsMjmA8!H;}xHTb9cXL?E z?q?|I%1egQv_gevf@18?^%k{}rgHpoq${=??G-ZBx^;CbPoEk2)d!1z94(d)(4YI( z)pEc4|00<&$y=m&f2_a*JhZR->qs!-z4nzjRyB0K?HC2T29$ggdyiay@7f=bjbB@t zyRAHJj)}OODwz^%`uOp&(a4vqm|l%eAfR(j{sH!MqG6jBy%(BYf;P58QJ>QgZJM#0 zTk_noKYL)U*dfdY?Wu8me6BrO&%>U9k zTk&EXA!vbO|0$b!sP-x~41)Ao-`qHMoy>ku`0Fs6Fou_3fNv9vAJs>y$4bGv&I5<~ zh+70!S3FEem@z3_YCA=3Jbl}viKjrNSiM)~G7E59ubDSf6UNDUzI|V}^}9$Y!S_ES zbNohJanN6}e_n*S_RMPFe9H>e>tXltF~q#s|2(pVN-%eG0!N@FgC8nIktjNG;A|UB z-EDB0m1Y*JcmF(0ejgkhEZbNzd+u~UdDvM|^9JOx-=a1JOqjL))_7AQQWIzDin1I} zHLfNKqxkhH9|#@A=KPl8{A)eRlw+;A$whWDMtcO|T7~la2Ri&;gFbxax=$^v*wbt< z02mrJhrbdb>Sq4M$eSEHJ}gC1us=|0OGc^<;@qktDtU=!@qg>KIuJ_r9^vq>yWPg= zOjAD`IJU9MF>YrhOGT0SmFg&M^vIrf$qq7vRvSobgw`a4RI?!6+91E$&YM}-!1{wE z8N-?%X+w%}!=p9y$_iV51L<2;tCl^jXRuEy_pf=YSXBJH?oNgx##LEO2g1@eD$ie7 z=gXHZ_FfHb)%CI@q2FRE{wP(>n1^VIgaEYIXAf%8?$8@oM3hdL>ZCgOD|iTc(}i{T zd!Cz}CuMA9Vkm~3!tie0q6u7LkujhkLx~4T}voM`3V*`swg~JFcRq} zwM1$Vb}}&xS7lhma`0X&FzmswgJj$M`QTcc^`SvW9Fj9;ml3Vqt_I_j=y<~UC zuEfl2@~fJtuq4g|dM0+Kh4o@lTD&8Y{KcDj-dBiC`*rQV-J{d~&2!JA>~~MMso<_c z3?#Vp-k9n=w$5J^aMWKDfO8E`?o&snZo&_-B~k-qYDy>P&Br9_R6($&H@?m>DZ_zQ zF3@lp2qR126t@@uQe%+ob@d7POeLum;{ARPowSlB{s!<{Wn44{WtqAU@q~mF5AlWm zfZkI*L;~j3rZjPuxx#Q={qq$$p2w_d>>Z}sLG$Qh-#sm}L&pu|@4_}uHm>^q~ zW>}0gTFlW_efYYswvCdyd@Vi^8da%36baBYe*g~cuqy2(oWdKHIrq^_2=i-yOwq?v zAb&KwU-4c(BM8-hm&<)|$q@G|(_*SG^Bl0oRRcI7WyR3zQ0kdL>&$# zMJAoU#5_K7TqKNnnD(YBshGuRpj%zp06c4I1Cb~&r5m2P_>WCJ?dP4|G9(bNWjCD7 zSY?sbF(pH%dESzFD2fTJ2!kk#n-}=fia4$`LJ2c$@EB+HsB(n)q9yyozuShpv**nN z)opq55#R(UNyAHvvF3P4BdAfRzvD`QLXo?}Q1f`qcxY(wHd~JQa_;x|4WH-Io~eN} zZa9)!mOAvC23>zdoJc%mFU8kbEWfTj_JMLJH$th$RJN;#nHKTG zre(X+G++_oPGjp3LxS)dr-HJG5;Z>H0l9H$GB>lVgTg5kNJ)%jJ#>gg$QVJYKmM?M z<>CXvAE_Ygb3EWn0FiU(exS$Z^Jc5(hw7n#6yQFfz~Ml_@kHPZDSleNbKm$D`%2sK zuXV4_@xg>jSg@?-p%#U~U5n?mg0xn2DuZG`+}sc=JbuTf;hu$IO40z5)>iM zkGsukt5@N+{+H&hK!%J6#1t;*rO$CRho?0h4W(c)<2m&g;Lq|z1%hiJ8xvF6H&h68O~9)z5iBYdVqD(pCtFl^Bt$6{#A(Lh3E}>g&lih3z;o@O}rCwxoPe@#B@j))0*kOLG3dKA3KpU+0Xh{z+{kJI=YEU zZwalmpVirSWduF02zJZxq4SEU)eHjLAZye=L{vau_-@z+yCxJN_M)mt zn%?-;)Vr1Qw)FFS?cb`-bn9O3rgh`onROsiv9@g`X#d@ z70q$uymjzpG)pA1IfEOj>4G8G>Bbts4tQLu zTH${(?Fj39dUhOTf|sWd;J7(Q-Ziq>;&_kaxNYdSexD*OHx*=w?B>b$CoW}Uyneoa zkme3PSxsC&l}zX5-^r%910tbbu%?FPVMkg(B40UJRjgu4}ON85?J^ zf%KtSN9UX)8Jzx;uzRf?sykWGSX%T!(Ya?|%*TE@%g&b9p3{BSF*ZB3B~s=JKvw^m zgtH2}c{%y0X|xq=H6iJTl;D`%Zac|*hQqS--Q5zq(#w9c5;eS+|Keaq)cm~x3GkMye;|uHhiJeqEt)o zX@i!)=qo0gLqD_|1hz9w(F?|~T`FC~2L+lK|24-|AP+U0P$z!ob_&O#(X7sr7S7lq{G;lH8H*N;|`Al?a+ghLTz;;HBpVcc+7@Ii2`q}bHg&g^ux04LS ziQurYvhrh`ysic03cDV3>SdijKeMmu52!udM!^ZjsEqnLZhPrhlzwT~Qy@GCK#Vo9 z`QavbGbwA(`C&>d801aL|9&Nk;c2y8!D8R&##35nhz%8Zu_k45$6KFR@oi?--Ff!8*ra-&;THPmReng1n`W(^Urj z)M_V|$LhBPK40^T>{_nD-F81DLd?6*!(~<=WRYxnW67Wf3M~gt<_~~ zz_unQ2ZWVv{z5+`;4~Pp6p)uK zG9GZ0?q6qck@n|MT7ja( zYIwLjEcpD(uefOK?d=Q;d8ugx9s#$@J^}Z;)sH$#K{PJ=VNz-?Cia#5yLV+nSksMX z*rcK^S`?zb0;D1$8mO?Hz6X~=YocP`w$$JU;ND-)&(giN$~39`qbhZH)*hdZE1RIM zMThMgAP_AtQw0cvdsGw;HJt7oocS|XllvnFZ3x#c93XmHT9QQ_1;bpO)APH=3_-O( z@3WXMt)eS0i%QxizwcrWIwRhdh_x2}?^6EJL9kPtyrLT>-liu;a4{zPX&)U8Y~`*5 z2Z6F1b;_`rvoji|u;5m0G>2_#^@)L8KHwMg!4ZS0 z?~X!IEdtBvME)UCX(J2IPl<{au6x(UwT9=jv~A+YznuX_xlTeIOf2VZ-u7OCSGMbu zg5J8aQ&#O?4BK{sH!of(-t=R0r;qW}Je!_=jXeK`>crGmQO$}YR`0zJKqmW^*JMI} z%19aMWt4jCz&`Cx{4DC2SlQ)Y!NKZ*#8R4pT{Qx0&-vL0r|sASck7YUrsxfp^dD#z zHmhANzI3rrW`Bd~W(-iN-+Gpb*3F|L2o#nsH5qJvOP$MZ?B#{*Lm}q-^4qA@XIaV5 zDB!)fGr9g`Hgm=8(s0b;8b#7e4wvsU-|2z2J>m!ig|ULC2z+H&Y4$oI_BQj{J@PHq z_l4%XS)8$XQ%&r4V*T;T(m$rW{4iQeXn%*GFF%Nh4=4s*3V!3*V&b{WAkE*`F4C@hlfD)#N6cu zHTe53ManPLiJ+LcFXA~q^w|*rMCHAj;4B9_{ZZO2dC#rwRBKAQs%vFmv`9aastC?11e80302r1|ntqTr>Z zgF#s#_S&TI6@}n%ieobo8JSEYFBo<{Q3j>1P}BgT zZ3x@5WuW@Ol=@S56RFuh>0dpjK0oD)tybycjs^Aw_D^beqwsJ#e-2M!n9T5YNG|`AZ zJ}pF`#k~mpP^30AvL$^|*vZeJt2+7D_i4dU&g(CSt7p!zQ`GT})&MoW+8yQ40gupu zvYELm_T2YELD)#Jd19$F?i`>>=f?-yD+5h7dIRC+voQtYPS=I_ySHzihHz8}0)@%O zSC3|zNc{bhlS91iIo%ufebO46=S0!-9pbvNc=l#5_JMg$3`|4$H_5VXuoQtHE zsTYo8LsO%t>wh@Acds*Aas4_LheVNyTxCz01yE(DeK;ys;wKx@uOLxGNjQ{bD_>k` zz8!e)_>`ja<{t9sjui4a#9uSPgXB&|D)yQ@9K$w3F5V%$zrSSXX&U>Q=z3l@Yz!Joe7M>hE`eekNRnXmb3_uZq-Z}~R6{M&P-VU_R4wvHeW zKz08E2d_N_MdouMdJ;i7XZu>QVp#w&LsnSySg!oJeid0r&*p}N!a4ZnNHn+uA%j&F z4})F!&wdzDe?(^aXAj2Pd<~`)h;$hx77=|MPmR@)6pdRend|^law2Elh{6^V$YfO5 zx`nhtjnXdi=>h~snHDI}VssvfT}~_7J-C*VqKWvj=CiSML5w5`5J1Nu7j>U_iY0jy zRovFMYt@XVj>N^FSA)QXtWdC1|Eo$Qv}I)Z-t{O!z06L$MHX9x`*0L&b{~!Y6A7~x zYCza8H=meH_kB7g`4=LQZ2<$VYF=_o!ZO|5G`J|{;MPK6h6|o$nkkGk zRUp!9L8uaognpvaI)Amvtnbe!Bd=Y0&HQFs=#IVr#8y_}$55SkTY6$mqOUD~bvG&h zp_mBdOlL@z0elbb>dFHV;yne)N7i<1tD|s&ex!~g!D%W}l4m+zpJ-NHjBZa}n7C$?5n8tTSuM_5LOU!fd#~cIR&g)ceo$VWtjGp%*My)VWGg!>8~Rq!58X z=-vpvh(Bae^sUe-;pZQ2@^Y!vix3b4TtE*qAuJBKIer#DX@XNMXx;IQ(oiBd!>hNLzQ7P;3r9ri}CSI)_P~LDN|-H*jU-UwzqBpuwsv2gkbMDz>HFL2C|TBa7AHb|`YnO|e(L>d^GRDRbLa1RZT9xI06E=F zaUh^14gW-ttM%eJldZkU{LlDZc^WFRmeSg#Hi1m1u6*)^SuaKqc8NCv!_N@u&L6rj z`RrVhVxFEbiI496N%5isvz3N1RpC#Qiv4ME;NNpZWQK8^Qt~N@$B2qdiEhYx_mg@! zWrS4JUzayYgR4GdS`Z*I~h6DEsn^A9-L5H(#TZZ{*$$OU_ASDjV(|oMy zapV88wW4yr`abz;Vh%?I$bwn;;=1IcPao&!dbeosaiopzi^G_4YTmkRIVs^L$~Bf_ z25l%M*nivB%ui!V;3;nJ6#$~D5l9AE*)kr*NQ3{}2AlgHaOdu<)c>v?pRyX|=H`}5 z{WjTu?3`8a0xY!sprGtmI()gU*>+sK95`3?q{4O9ay)N05x;+Sc6VbWT)nMjaJj@s!twPtImKST{Y=Vy` zV{qHg4<<51D1RwCf6i!ioc8%5{K#Gr_j(Z^d?C+W?f?V?&3s+{q;IS3@m{uI;5pKB zVlX|_X2Q5;Z3hCzoDu-Yyd1u#z#gi>ZuCjKFm_=`E2%-?)gMxES0h6RVIPby&N3IS z-{M#LAUX!{Tb#uDic`PrwZbtv+nuuf1Q0 zMa-eYP&(0-1oPXs_wKB=5=X>4=-GXfUbhFnREU3gb-)MKeWX>>9tBZdzRI8kxx0e^ zh$TTfB`8&f(woO<*5$g;+49$T%*|IVMqhiw(d{~3_Nd>*(6SKRy59ghKXX5#14um| zMc>Yr*PYZvzj+S41b1wAN08@Y{3d}F-{5KXUY`GxZ0fWBb=wxTmOhQ$y%p+_@)s-H zAgMpW0TCXTFvon$JYk4DIP<%k~)ooPhe?{$qCso(Ah5rj9y45#614YSzYX7Tvj}v z1$cVsZh`=?mR-EdZ0)TJS)Hw|O#+qI$_@XBPg(i}*F_B`F%i8S6ijpZ7A0F&ju8aJ z0w|+9LQGLKIxMK3*TGbr58`HM(!ZMAdGe?wKE_7E8@LZ~tvMgZ+67$S##FVym%fjl zU#uj(52kfKlw_rU8)*3u;In>D(JEAK2i<+{9o7XyXZ@Ue(e%bl9Uiq&O!M|p4lkns>aC?GkV$=hgtI03{=??<$8=_z&GzfV69UYs zYDEzUR>o*-Fu$nCNts>+m(qEDdL|sa^=`?|t);~IPp>7zr1ux6-fB!=r38w+DU9Tw zHtk?}thCpiuht5Z`_lcUGnBG6WED0>ld`^VL1gh^%ze<3APquum;z2GRbm~U+SJ#jHwSC#qJk@2*Un*qtv5{;`IBzNIAQ{4>c z3yR%uI6ZPPrgt@`%>Sz``np2gDk+Oi70TD_A2L-;+=r4$@}onaGpv%VS&y z=qxESr9q00SC-~tullx6qeh0NCIAA$!v={{{=feG9bO2?(ZiVGVNV + + opencs.png + + From 6356d3a385c7f1a1df5ce25267021f4d6833be45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Feb 2013 06:02:57 -0800 Subject: [PATCH 0355/1483] Start actors with collision enabled NPCs are now affected by gravity. The player still starts in no-collision mode though, since they start in the void rather than a door marker. --- libs/openengine/bullet/physic.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 2b26c3a487..7ffe071895 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -29,8 +29,11 @@ namespace Physic PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) - , mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + , mBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) { + // FIXME: Force player to start in no-collision mode for now, until he spawns at a proper door marker. + if(name == "player") + collisionMode = false; mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); From 00db13be32d0ec107541e3427934117e900fb152 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 15:56:22 +0100 Subject: [PATCH 0356/1483] Reverted previous commits, and handle disallowed inventory in MWWorld::Class. Wanted to avoid this, but the previous solution broke teleport door sounds. Also fixed book/scroll window take button showing when inventory was not allowed. --- apps/openmw/mwclass/apparatus.cpp | 4 ++++ apps/openmw/mwclass/armor.cpp | 4 ++++ apps/openmw/mwclass/clothing.cpp | 4 ++++ apps/openmw/mwclass/container.cpp | 4 ++++ apps/openmw/mwclass/ingredient.cpp | 4 ++++ apps/openmw/mwclass/light.cpp | 3 +++ apps/openmw/mwclass/lockpick.cpp | 4 ++++ apps/openmw/mwclass/misc.cpp | 4 ++++ apps/openmw/mwclass/potion.cpp | 4 ++++ apps/openmw/mwclass/probe.cpp | 4 ++++ apps/openmw/mwclass/repair.cpp | 4 ++++ apps/openmw/mwclass/weapon.cpp | 4 ++++ apps/openmw/mwgui/bookwindow.cpp | 15 ++++++++++++--- apps/openmw/mwgui/bookwindow.hpp | 5 +++++ apps/openmw/mwgui/scrollwindow.cpp | 15 ++++++++++++--- apps/openmw/mwgui/scrollwindow.hpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++++++++++++++- apps/openmw/mwworld/action.cpp | 4 +++- apps/openmw/mwworld/action.hpp | 3 +-- apps/openmw/mwworld/actionalchemy.cpp | 3 +-- apps/openmw/mwworld/actionalchemy.hpp | 2 +- apps/openmw/mwworld/actionapply.cpp | 6 ++---- apps/openmw/mwworld/actionapply.hpp | 4 ++-- apps/openmw/mwworld/actioneat.cpp | 4 +--- apps/openmw/mwworld/actioneat.hpp | 2 +- apps/openmw/mwworld/actionequip.cpp | 4 +--- apps/openmw/mwworld/actionequip.hpp | 2 +- apps/openmw/mwworld/actionopen.cpp | 5 ++--- apps/openmw/mwworld/actionopen.hpp | 2 +- apps/openmw/mwworld/actionread.cpp | 3 +-- apps/openmw/mwworld/actionread.hpp | 2 +- apps/openmw/mwworld/actiontake.cpp | 7 +------ apps/openmw/mwworld/actiontake.hpp | 2 +- apps/openmw/mwworld/actiontalk.cpp | 4 +--- apps/openmw/mwworld/actiontalk.hpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 3 +-- apps/openmw/mwworld/actionteleport.hpp | 2 +- apps/openmw/mwworld/failedaction.cpp | 9 ++++----- apps/openmw/mwworld/failedaction.hpp | 4 ++-- apps/openmw/mwworld/nullaction.hpp | 2 +- 40 files changed, 127 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 06467bb21a..2c561eb858 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -12,6 +12,7 @@ #include "../mwworld/actionalchemy.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -61,6 +62,9 @@ namespace MWClass boost::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action( new MWWorld::ActionTake (ptr)); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 704173b1c4..654cb87fd6 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -15,6 +15,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -64,6 +65,9 @@ namespace MWClass boost::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index c411bb1930..892ac091ce 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index bbe005955c..a2d75131eb 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/failedaction.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/cellstore.hpp" @@ -85,6 +86,9 @@ namespace MWClass boost::shared_ptr Container::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + const std::string lockedSound = "LockedChest"; const std::string trapActivationSound = "Disarm Trap Fail"; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 7ad8f1b47c..bbba45df58 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -13,6 +13,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwworld/actioneat.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwmechanics/npcstats.hpp" @@ -72,6 +73,9 @@ namespace MWClass boost::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index b94b0d395b..235e57d375 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -88,6 +88,9 @@ namespace MWClass boost::shared_ptr Light::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index a667fefb2a..7e909437cf 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index a21cc2aef6..d43a44359f 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -65,6 +66,9 @@ namespace MWClass boost::shared_ptr Miscellaneous::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 09d152de77..c3a6df2112 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -13,6 +13,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action( new MWWorld::ActionTake (ptr)); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 0d8653aa87..a28be17e7e 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -61,6 +62,9 @@ namespace MWClass boost::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index edb28d16c2..39a7f65e07 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -11,6 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -60,6 +61,9 @@ namespace MWClass boost::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index c8fe0d2768..d8c11558cc 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 659795e188..777751069b 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -14,8 +14,10 @@ using namespace MWGui; -BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_book.layout", parWindowManager) +BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_book.layout", parWindowManager) + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); @@ -85,7 +87,14 @@ void BookWindow::open (MWWorld::Ptr book) void BookWindow::setTakeButtonShow(bool show) { - mTakeButton->setVisible(show); + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); +} + +void BookWindow::setInventoryAllowed(bool allowed) +{ + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 5887975ea4..a509f131fe 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -17,6 +17,8 @@ namespace MWGui void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); + void setInventoryAllowed(bool allowed); + protected: void onNextPageButtonClicked (MyGUI::Widget* sender); void onPrevPageButtonClicked (MyGUI::Widget* sender); @@ -40,6 +42,9 @@ namespace MWGui std::vector mPages; MWWorld::Ptr mBook; + + bool mTakeButtonShow; + bool mTakeButtonAllowed; }; } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 8317025e0b..3bd3a47439 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,8 +12,10 @@ using namespace MWGui; -ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_scroll.layout", parWindowManager) +ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_scroll.layout", parWindowManager) + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { getWidget(mTextView, "TextView"); @@ -50,7 +52,14 @@ void ScrollWindow::open (MWWorld::Ptr scroll) void ScrollWindow::setTakeButtonShow(bool show) { - mTakeButton->setVisible(show); + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); +} + +void ScrollWindow::setInventoryAllowed(bool allowed) +{ + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 7932a215b8..42b6395a9a 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -15,6 +15,7 @@ namespace MWGui void open (MWWorld::Ptr scroll); void setTakeButtonShow(bool show); + void setInventoryAllowed(bool allowed); protected: void onCloseButtonClicked (MyGUI::Widget* _sender); @@ -26,6 +27,10 @@ namespace MWGui MyGUI::ScrollView* mTextView; MWWorld::Ptr mScroll; + + bool mTakeButtonShow; + bool mTakeButtonAllowed; + }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e360aad19b..e03b91216d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -109,7 +109,6 @@ WindowManager::WindowManager( , mHudEnabled(true) , mTranslationDataStorage (translationDataStorage) { - // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); mGui = mGuiManager->getGui(); @@ -196,6 +195,9 @@ WindowManager::WindowManager( unsetSelectedSpell(); unsetSelectedWeapon(); + if (newGame) + disallowAll (); + // Set up visibility updateVisible(); } @@ -943,12 +945,23 @@ bool WindowManager::isAllowed (GuiWindow wnd) const void WindowManager::allow (GuiWindow wnd) { mAllowed = (GuiWindow)(mAllowed | wnd); + + if (wnd & GW_Inventory) + { + mBookWindow->setInventoryAllowed (true); + mScrollWindow->setInventoryAllowed (true); + } + updateVisible(); } void WindowManager::disallowAll() { mAllowed = GW_None; + + mBookWindow->setInventoryAllowed (false); + mScrollWindow->setInventoryAllowed (false); + updateVisible(); } diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 0d50d8deda..a5199fb3ea 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -18,7 +18,7 @@ MWWorld::Action::~Action() {} void MWWorld::Action::execute (const Ptr& actor) { - if (!mSoundId.empty() & executeImp (actor)) + if (!mSoundId.empty()) { if (mKeepSound && actor.getRefData().getHandle()=="player") { @@ -35,6 +35,8 @@ void MWWorld::Action::execute (const Ptr& actor) mKeepSound ? MWBase::SoundManager::Play_NoTrack : MWBase::SoundManager::Play_Normal); } } + + executeImp (actor); } void MWWorld::Action::setSound (const std::string& id) diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index 42c2ad0844..d8e5d93bb2 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -18,8 +18,7 @@ namespace MWWorld Action (const Action& action); Action& operator= (const Action& action); - /// @return true if the sound should be played, false if not (e.g. if the action is not allowed) - virtual bool executeImp (const Ptr& actor) = 0; + virtual void executeImp (const Ptr& actor) = 0; protected: diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index 20093279e0..bba75bc499 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -5,9 +5,8 @@ namespace MWWorld { - bool ActionAlchemy::executeImp (const Ptr& actor) + void ActionAlchemy::executeImp (const Ptr& actor) { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy); - return true; } } diff --git a/apps/openmw/mwworld/actionalchemy.hpp b/apps/openmw/mwworld/actionalchemy.hpp index 814f347c88..e6d1a7976c 100644 --- a/apps/openmw/mwworld/actionalchemy.hpp +++ b/apps/openmw/mwworld/actionalchemy.hpp @@ -7,7 +7,7 @@ namespace MWWorld { class ActionAlchemy : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); }; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 2a41b5613f..f78b8f7988 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -9,10 +9,9 @@ namespace MWWorld : Action (false, target), mId (id) {} - bool ActionApply::executeImp (const Ptr& actor) + void ActionApply::executeImp (const Ptr& actor) { MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor); - return true; } @@ -21,10 +20,9 @@ namespace MWWorld : Action (false, target), mId (id), mSkillIndex (skillIndex), mUsageType (usageType) {} - bool ActionApplyWithSkill::executeImp (const Ptr& actor) + void ActionApplyWithSkill::executeImp (const Ptr& actor) { if (MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor) && mUsageType!=-1) MWWorld::Class::get (getTarget()).skillUsageSucceeded (actor, mSkillIndex, mUsageType); - return true; } } diff --git a/apps/openmw/mwworld/actionapply.hpp b/apps/openmw/mwworld/actionapply.hpp index 53b2de1d08..3353ae0eed 100644 --- a/apps/openmw/mwworld/actionapply.hpp +++ b/apps/openmw/mwworld/actionapply.hpp @@ -13,7 +13,7 @@ namespace MWWorld { std::string mId; - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: @@ -26,7 +26,7 @@ namespace MWWorld int mSkillIndex; int mUsageType; - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 81c45f051e..63efff738e 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -16,7 +16,7 @@ namespace MWWorld { - bool ActionEat::executeImp (const Ptr& actor) + void ActionEat::executeImp (const Ptr& actor) { // remove used item getTarget().getRefData().setCount (getTarget().getRefData().getCount()-1); @@ -42,8 +42,6 @@ namespace MWWorld // increase skill Class::get (actor).skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } - - return true; } ActionEat::ActionEat (const MWWorld::Ptr& object) : Action (false, object) {} diff --git a/apps/openmw/mwworld/actioneat.hpp b/apps/openmw/mwworld/actioneat.hpp index 265f5aa68a..ce5330db77 100644 --- a/apps/openmw/mwworld/actioneat.hpp +++ b/apps/openmw/mwworld/actioneat.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionEat : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 902e0fdb69..2d257aa614 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -16,7 +16,7 @@ namespace MWWorld { } - bool ActionEquip::executeImp (const Ptr& actor) + void ActionEquip::executeImp (const Ptr& actor) { MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); @@ -113,7 +113,5 @@ namespace MWWorld /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); - - return true; } } diff --git a/apps/openmw/mwworld/actionequip.hpp b/apps/openmw/mwworld/actionequip.hpp index fb3a1ac10e..3b56c74027 100644 --- a/apps/openmw/mwworld/actionequip.hpp +++ b/apps/openmw/mwworld/actionequip.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionEquip : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: /// @param item to equip diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index da570dff02..040a3856e8 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -14,13 +14,12 @@ namespace MWWorld { } - bool ActionOpen::executeImp (const MWWorld::Ptr& actor) + void ActionOpen::executeImp (const MWWorld::Ptr& actor) { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return false; + return; MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget()); - return true; } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 42ad4aecbe..c49ebefa51 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -10,7 +10,7 @@ namespace MWWorld { class ActionOpen : public Action { - virtual bool executeImp (const MWWorld::Ptr& actor); + virtual void executeImp (const MWWorld::Ptr& actor); public: ActionOpen (const Ptr& container); diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 157b051d6f..6d5d9d8fde 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -19,7 +19,7 @@ namespace MWWorld { } - bool ActionRead::executeImp (const MWWorld::Ptr& actor) + void ActionRead::executeImp (const MWWorld::Ptr& actor) { LiveCellRef *ref = getTarget().get(); @@ -53,6 +53,5 @@ namespace MWWorld npcStats.flagAsUsed (ref->mBase->mId); } - return true; } } diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index dfb536c64a..00a4756dda 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionRead : public Action { - virtual bool executeImp (const MWWorld::Ptr& actor); + virtual void executeImp (const MWWorld::Ptr& actor); public: /// @param book or scroll to read diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index fef8a7e73a..cdd19b46e4 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -12,18 +12,13 @@ namespace MWWorld { ActionTake::ActionTake (const MWWorld::Ptr& object) : Action (true, object) {} - bool ActionTake::executeImp (const Ptr& actor) + void ActionTake::executeImp (const Ptr& actor) { - if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return false; - // insert into player's inventory MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPtr ("player", true); MWWorld::Class::get (player).getContainerStore (player).add (getTarget()); MWBase::Environment::get().getWorld()->deleteObject (getTarget()); - - return true; } } diff --git a/apps/openmw/mwworld/actiontake.hpp b/apps/openmw/mwworld/actiontake.hpp index 2a87156d0a..b0a9b82478 100644 --- a/apps/openmw/mwworld/actiontake.hpp +++ b/apps/openmw/mwworld/actiontake.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionTake : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 6bee9eb26e..905497f85b 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -3,15 +3,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwbase/inputmanager.hpp" namespace MWWorld { ActionTalk::ActionTalk (const Ptr& actor) : Action (false, actor) {} - bool ActionTalk::executeImp (const Ptr& actor) + void ActionTalk::executeImp (const Ptr& actor) { MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); - return true; } } diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp index 91c71dc79b..b88b168d8c 100644 --- a/apps/openmw/mwworld/actiontalk.hpp +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionTalk : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 9b21cc8763..ae5ffc3b90 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -12,12 +12,11 @@ namespace MWWorld { } - bool ActionTeleport::executeImp (const Ptr& actor) + void ActionTeleport::executeImp (const Ptr& actor) { if (mCellName.empty()) MWBase::Environment::get().getWorld()->changeToExteriorCell (mPosition); else MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, mPosition); - return true; } } diff --git a/apps/openmw/mwworld/actionteleport.hpp b/apps/openmw/mwworld/actionteleport.hpp index 4f771cac99..a13cb61b21 100644 --- a/apps/openmw/mwworld/actionteleport.hpp +++ b/apps/openmw/mwworld/actionteleport.hpp @@ -14,7 +14,7 @@ namespace MWWorld std::string mCellName; ESM::Position mPosition; - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index e2ca78b2c7..ec763dba01 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -11,12 +11,11 @@ namespace MWWorld { } - bool FailedAction::executeImp (const Ptr& actor) + void FailedAction::executeImp (const Ptr& actor) { if ( actor.getRefData().getHandle()=="player" && !(message.empty())) - { - MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); - } - return true; + { + MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); + } } } diff --git a/apps/openmw/mwworld/failedaction.hpp b/apps/openmw/mwworld/failedaction.hpp index 7d64afe74b..e736bfb63b 100644 --- a/apps/openmw/mwworld/failedaction.hpp +++ b/apps/openmw/mwworld/failedaction.hpp @@ -10,11 +10,11 @@ namespace MWWorld { std::string message; - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: FailedAction (const std::string& message = std::string()); }; } -#endif +#endif \ No newline at end of file diff --git a/apps/openmw/mwworld/nullaction.hpp b/apps/openmw/mwworld/nullaction.hpp index f5544e4c10..7ef8b4a065 100644 --- a/apps/openmw/mwworld/nullaction.hpp +++ b/apps/openmw/mwworld/nullaction.hpp @@ -8,7 +8,7 @@ namespace MWWorld /// \brief Action: do nothing class NullAction : public Action { - virtual bool executeImp (const Ptr& actor) {return false;} + virtual void executeImp (const Ptr& actor) {} }; } From d899f334444665ef073ac3d6f77623000f7831d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 16:00:31 +0100 Subject: [PATCH 0357/1483] Race/Class/Birth dialogs: immediately enable OK buttons since they have a preselected entry now. --- apps/openmw/mwgui/birth.cpp | 3 --- apps/openmw/mwgui/class.cpp | 3 --- apps/openmw/mwgui/race.cpp | 3 --- 3 files changed, 9 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 99d6605d33..c53a68cf44 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -48,7 +48,6 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); - okButton->setEnabled(false); updateBirths(); updateSpells(); @@ -85,7 +84,6 @@ void BirthDialog::setBirthId(const std::string &birthId) mBirthList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -114,7 +112,6 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *birthId = mBirthList->getItemDataAt(_index); if (boost::iequals(mCurrentBirthId, *birthId)) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 475efaab31..2eed21a528 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -104,7 +104,6 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); - okButton->setEnabled(false); updateClasses(); updateStats(); @@ -140,7 +139,6 @@ void PickClassDialog::setClassId(const std::string &classId) mClassList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -169,7 +167,6 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *classId = mClassList->getItemDataAt(_index); if (boost::iequals(mCurrentClassId, *classId)) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index df6c993401..054cce7b85 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -81,7 +81,6 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); - okButton->setEnabled(false); updateRaces(); updateSkills(); @@ -135,7 +134,6 @@ void RaceDialog::setRaceId(const std::string &raceId) mRaceList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -258,7 +256,6 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *raceId = mRaceList->getItemDataAt(_index); if (boost::iequals(mCurrentRaceId, *raceId)) return; From 5a11ddc485db96390d2bce1e07460ac3def4ff68 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 16:01:36 +0100 Subject: [PATCH 0358/1483] Pressing F1 again hides the quick keys menu. --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 02a699eced..b065b7f7fd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -638,6 +638,8 @@ namespace MWInput { if (!mWindows.isGuiMode ()) mWindows.pushGuiMode (MWGui::GM_QuickKeysMenu); + else if (mWindows.getMode () == MWGui::GM_QuickKeysMenu) + mWindows.removeGuiMode (MWGui::GM_QuickKeysMenu); } void InputManager::activate() From 7ffcfa36220cd3a53e168e12abab8b0afdeb6b8d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 16:23:55 +0100 Subject: [PATCH 0359/1483] Water and clouds no longer depend on timescale. --- apps/openmw/mwrender/renderingmanager.cpp | 2 -- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwrender/water.cpp | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ce48284e09..fe8f3e99bf 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -353,8 +353,6 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(0.f); return; } - Ogre::ControllerManager::getSingleton().setTimeFactor( - MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); mPlayer->update(duration); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index ce8d826320..be989724a9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -361,7 +361,7 @@ void SkyManager::update(float duration) mRootNode->setPosition(mCamera->getDerivedPosition()); // UV Scroll the clouds - mCloudAnimationTimer += duration * mCloudSpeed * (MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); + mCloudAnimationTimer += duration * mCloudSpeed; sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", sh::makeProperty(new sh::FloatValue(mCloudAnimationTimer))); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 3b8705ac56..33159024ee 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -399,7 +399,7 @@ void Water::update(float dt, Ogre::Vector3 player) mUnderwaterDome->setPosition (pos); */ - mWaterTimer += dt / 30.0 * MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + mWaterTimer += dt; sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); From 50d61a5b6e057c194f4fddb4d12ee910e1295cda Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Feb 2013 17:27:25 +0100 Subject: [PATCH 0360/1483] proper implementation of gmst type column --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 5 +- apps/opencs/view/doc/viewmanager.cpp | 5 + apps/opencs/view/world/enumdelegate.cpp | 101 ++++++++++++++++++++ apps/opencs/view/world/enumdelegate.hpp | 57 ++++++++++++ apps/opencs/view/world/util.cpp | 25 ++++- apps/opencs/view/world/util.hpp | 12 ++- apps/opencs/view/world/vartypedelegate.cpp | 103 +++++++++++++++++++++ apps/opencs/view/world/vartypedelegate.hpp | 38 ++++++++ 10 files changed, 342 insertions(+), 9 deletions(-) create mode 100644 apps/opencs/view/world/enumdelegate.cpp create mode 100644 apps/opencs/view/world/enumdelegate.hpp create mode 100644 apps/opencs/view/world/vartypedelegate.cpp create mode 100644 apps/opencs/view/world/vartypedelegate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8cee3f0f4e..083aa96304 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -59,7 +59,7 @@ opencs_units (view/world ) opencs_units_noqt (view/world - dialoguesubview util subviews + dialoguesubview util subviews enumdelegate vartypedelegate ) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index f1871a6a94..40581972e9 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -29,7 +29,8 @@ namespace CSMWorld Display_String, Display_Integer, Display_Float, - Display_Var + Display_Var, + Display_VarType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index cfbd804a5a..2d81a24e90 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -79,7 +79,7 @@ namespace CSMWorld int mType; FixedRecordTypeColumn (int type) - : Column ("Type", ColumnBase::Display_Integer, 0), mType (type) {} + : Column ("Record Type", ColumnBase::Display_Integer, 0), mType (type) {} virtual QVariant get (const Record& record) const { @@ -92,10 +92,11 @@ namespace CSMWorld } }; + /// \attention A var type column must be immediately followed by a suitable value column. template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_Integer) {} + VarTypeColumn() : Column ("Type", ColumnBase::Display_VarType) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 2a6309da1c..473049999c 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -7,6 +7,8 @@ #include "../../model/doc/document.hpp" #include "../world/util.hpp" +#include "../world/enumdelegate.hpp" +#include "../world/vartypedelegate.hpp" #include "view.hpp" @@ -32,6 +34,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType, + new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float)); } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp new file mode 100644 index 0000000000..7a8b45373d --- /dev/null +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -0,0 +1,101 @@ + +#include "enumdelegate.hpp" + +#include + +#include +#include +#include + +#include "../../model/world/commands.hpp" + +void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + if (QComboBox *comboBox = dynamic_cast (editor)) + { + QString value = comboBox->currentText(); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + if (iter->second==value) + { + addCommands (model, index, iter->first); + break; + } + } +} + +void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const +{ + getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); +} + + +CSVWorld::EnumDelegate::EnumDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent) +: CommandDelegate (undoStack, parent), mValues (values) +{ + +} + +QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QComboBox *comboBox = new QComboBox (parent); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + comboBox->addItem (iter->second); + + return comboBox; +} + +void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const +{ + if (QComboBox *comboBox = dynamic_cast (editor)) + { + int value = index.data (Qt::EditRole).toInt(); + + std::size_t size = mValues.size(); + + for (std::size_t i=0; isetCurrentIndex (i); + break; + } + } +} + +void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QStyleOptionViewItemV4 option2 (option); + + int value = index.data().toInt(); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + if (iter->first==value) + { + option2.text = iter->second; + + QApplication::style()->drawControl (QStyle::CE_ItemViewItem, &option2, painter); + + break; + } +} + + +CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new EnumDelegate (mValues, undoStack, parent); +} + +void CSVWorld::EnumDelegateFactory::add (int value, const QString& name) +{ + mValues.push_back (std::make_pair (value, name)); +} diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp new file mode 100644 index 0000000000..f11252371e --- /dev/null +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -0,0 +1,57 @@ +#ifndef CSV_WORLD_ENUMDELEGATE_H +#define CSV_WORLD_ENUMDELEGATE_H + +#include + +#include + +#include + +#include "util.hpp" + +namespace CSVWorld +{ + /// \brief Integer value that represents an enum and is interacted with via a combobox + class EnumDelegate : public CommandDelegate + { + std::vector > mValues; + + private: + + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; + + virtual void addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const; + + public: + + EnumDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent); + + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + virtual void setEditorData (QWidget *editor, const QModelIndex& index) const; + + virtual void paint (QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + }; + + class EnumDelegateFactory : public CommandDelegateFactory + { + std::vector > mValues; + + public: + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + void add (int value, const QString& name); + }; + + +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 85fda2dad1..5ada1d84f3 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -88,6 +88,19 @@ const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFacto } +QUndoStack& CSVWorld::CommandDelegate::getUndoStack() const +{ + return mUndoStack; +} + +void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); +} + CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) : QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) {} @@ -97,14 +110,18 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode { if (!mEditLock) { - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + setModelDataImp (editor, model, index); } + ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. } -void CSVWorld::CommandDelegate::setEditLock (bool locked) +void CSVWorld::CommandDelegate::setEditLock (bool locked) { mEditLock = locked; +} + +bool CSVWorld::CommandDelegate::isEditLocked() const +{ + return mEditLock; } \ No newline at end of file diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 79f30da2c2..5334abf9c8 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -85,13 +85,23 @@ namespace CSVWorld QUndoStack& mUndoStack; bool mEditLock; + protected: + + QUndoStack& getUndoStack() const; + + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; + public: CommandDelegate (QUndoStack& undoStack, QObject *parent); - void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + virtual void setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; void setEditLock (bool locked); + + bool isEditLocked() const; }; } diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp new file mode 100644 index 0000000000..3ee759ef2b --- /dev/null +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -0,0 +1,103 @@ + +#include "vartypedelegate.hpp" + +#include + +#include "../../model/world/commands.hpp" + +void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type) + const +{ + QModelIndex next = model->index (index.row(), index.column()+1); + + QVariant old = model->data (next); + + QVariant value; + + switch (type) + { + case ESM::VT_Short: + case ESM::VT_Int: + case ESM::VT_Long: + + value = old.toInt(); + break; + + case ESM::VT_Float: + + value = old.toFloat(); + break; + + case ESM::VT_String: + + value = old.toString(); + break; + + default: break; // ignore the rest + } + + getUndoStack().beginMacro ( + "Modify " + model->headerData (index.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + + getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); + getUndoStack().push (new CSMWorld::ModifyCommand (*model, next, value)); + + getUndoStack().endMacro(); +} + +CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent) +: EnumDelegate (values, undoStack, parent) +{} + + +CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0, + ESM::VarType type1, ESM::VarType type2, ESM::VarType type3) +{ + if (type0!=ESM::VT_Unknown) + add (type0); + + if (type1!=ESM::VT_Unknown) + add (type1); + + if (type2!=ESM::VT_Unknown) + add (type2); + + if (type3!=ESM::VT_Unknown) + add (type3); +} + +CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new VarTypeDelegate (mValues, undoStack, parent); +} + +void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) +{ + struct Name + { + ESM::VarType mType; + const char *mName; + }; + + static const Name sNames[] = + { + { ESM::VT_None, "empty" }, + { ESM::VT_Short, "short" }, + { ESM::VT_Int, "long" }, + { ESM::VT_Long, "long" }, + { ESM::VT_Float, "float" }, + { ESM::VT_String, "string" }, + { ESM::VT_Unknown, 0 } // end marker + }; + + for (int i=0; sNames[i].mName; ++i) + if (sNames[i].mType==type) + { + mValues.push_back (std::make_pair (type, sNames[i].mName)); + return; + } + + throw std::logic_error ("Unsupported variable type"); +} diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp new file mode 100644 index 0000000000..621dd316b3 --- /dev/null +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -0,0 +1,38 @@ +#ifndef CSV_WORLD_VARTYPEDELEGATE_H +#define CSV_WORLD_VARTYPEDELEGATE_H + +#include "enumdelegate.hpp" + +namespace CSVWorld +{ + class VarTypeDelegate : public EnumDelegate + { + private: + + virtual void addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const; + + public: + + VarTypeDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent); + }; + + class VarTypeDelegateFactory : public CommandDelegateFactory + { + std::vector > mValues; + + public: + + VarTypeDelegateFactory (ESM::VarType type0 = ESM::VT_Unknown, + ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown, + ESM::VarType type3 = ESM::VT_Unknown); + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + void add (ESM::VarType type); + }; +} + +#endif From 791d16bbdb6ff95c1b4be0adfe04ab945601e4b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 18:12:38 +0100 Subject: [PATCH 0361/1483] Use infinite AAB for sky meshes to fix them from disappearing from underwater refraction, while still taking advantage of CPU culling for other meshes --- apps/openmw/mwrender/refraction.cpp | 4 ++++ apps/openmw/mwrender/sky.cpp | 6 ++++++ apps/openmw/mwrender/water.cpp | 4 +++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index e6b6e3baad..a924be7d74 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -41,6 +41,7 @@ namespace MWRender mRenderTarget->removeListener(this); Ogre::TextureManager::getSingleton().remove("WaterRefraction"); mParentCamera->getSceneManager()->destroyCamera(mCamera); + mParentCamera->getSceneManager()->removeRenderQueueListener(this); } void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) @@ -53,6 +54,9 @@ namespace MWRender mCamera->setAspectRatio(mParentCamera->getAspectRatio()); mCamera->setFOVy(mParentCamera->getFOVy()); + // enable clip plane here to take advantage of CPU culling for overwater or underwater objects + mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); + mRenderActive = true; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index be989724a9..3b02ca412f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -280,6 +280,9 @@ void SkyManager::create() mSunGlare->setRenderQueue(RQG_SkiesLate); mSunGlare->setVisibilityFlags(RV_NoReflection); + Ogre::AxisAlignedBox aabInf; + aabInf.setInfinite (); + // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif"); @@ -289,6 +292,7 @@ void SkyManager::create() night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); + night1_ent->getMesh()->_setBounds (aabInf); for (unsigned int j=0; jgetNumSubEntities(); ++j) { @@ -315,6 +319,7 @@ void SkyManager::create() atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); + atmosphere_ent->getMesh()->_setBounds (aabInf); } @@ -328,6 +333,7 @@ void SkyManager::create() clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); clouds_ent->setCastShadows(false); + clouds_ent->getMesh()->_setBounds (aabInf); } mCreated = true; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 33159024ee..b006059a9d 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -124,7 +124,6 @@ void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::St { if (queueGroupId < 20 && mRenderActive) { - // this trick does not seem to work well for extreme angles mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); } @@ -145,6 +144,9 @@ void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) pos.y = (mWaterPlane).d*2 - pos.y; mSky->setSkyPosition(pos); mCamera->enableReflection(mWaterPlane); + + // enable clip plane here to take advantage of CPU culling for overwater or underwater objects + mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); } void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) From 170a9762ac0127579c9df4cab14bc8d1732bb2f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 18:30:21 +0100 Subject: [PATCH 0362/1483] Fix travel services not actually costing gold. --- apps/openmw/mwgui/travelwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 9615e95f73..465f588b8a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -132,6 +132,8 @@ namespace MWGui if (mWindowManager.getInventoryWindow()->getPlayerGold()addOrRemoveGold (-price); + MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); ESM::Position pos = *_sender->getUserData(); From e1ca0a15aec61c1bcc3eba325b12476e0600b41a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 18:58:54 +0100 Subject: [PATCH 0363/1483] Add message box when item is added to player's inventory --- apps/openmw/mwscript/containerextensions.cpp | 23 +++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 4cce19b862..68ae1b516f 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -60,6 +60,27 @@ namespace MWScript } MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); + + // The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory + std::string msgBox; + std::string itemName = MWWorld::Class::get(ref.getPtr()).getName(ref.getPtr()); + if (count == 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); + std::stringstream temp; + temp << boost::format(msgBox) % itemName; + msgBox = temp.str(); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); + std::stringstream temp; + temp << boost::format(msgBox) % (count) % itemName; + msgBox = temp.str(); + } + + if(count > 0) + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); } }; @@ -130,7 +151,7 @@ namespace MWScript } } - /* The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory */ + // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory std::string msgBox; if(originalCount - count > 1) { From abd307d70e946b9efe259ce6c4ed54d8f2af6b53 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Feb 2013 19:26:01 +0100 Subject: [PATCH 0364/1483] Issue #567: workaround for crash with non-English ESX files --- apps/opencs/model/world/data.cpp | 6 +++++- apps/opencs/view/doc/opendialog.cpp | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f120c75f10..92bd2bdb04 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -72,7 +72,11 @@ void CSMWorld::Data::merge() void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) { ESM::ESMReader reader; - /// \todo set encoder + + /// \todo set encoding properly, once config implementation has been fixed. + ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252")); + reader.setEncoder (&encoder); + reader.open (path.string()); // Note: We do not need to send update signals here, because at this point the model is not connected diff --git a/apps/opencs/view/doc/opendialog.cpp b/apps/opencs/view/doc/opendialog.cpp index 9a5feb23a7..7b62aafa31 100644 --- a/apps/opencs/view/doc/opendialog.cpp +++ b/apps/opencs/view/doc/opendialog.cpp @@ -10,48 +10,48 @@ OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) QVBoxLayout *layout = new QVBoxLayout(this); mFileSelector = new DataFilesList(mCfgMgr, this); layout->addWidget(mFileSelector); - - //FIXME - same as DataFilesPage::setupDataFiles + + /// \todo move config to Editor class and add command line options. // We use the Configuration Manager to retrieve the configuration values boost::program_options::variables_map variables; boost::program_options::options_description desc; - + desc.add_options() ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) ("data-local", boost::program_options::value()->default_value("")) ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) ("encoding", boost::program_options::value()->default_value("win1252")); - + boost::program_options::notify(variables); - + mCfgMgr.readConfiguration(variables, desc); - + Files::PathContainer mDataDirs, mDataLocal; if (!variables["data"].empty()) { mDataDirs = Files::PathContainer(variables["data"].as()); } - + std::string local = variables["data-local"].as(); if (!local.empty()) { mDataLocal.push_back(Files::PathContainer::value_type(local)); } - + mCfgMgr.processPaths(mDataDirs); mCfgMgr.processPaths(mDataLocal); - + // Set the charset for reading the esm/esp files QString encoding = QString::fromStdString(variables["encoding"].as()); - + Files::PathContainer dataDirs; dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end()); dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end()); mFileSelector->setupDataFiles(dataDirs, encoding); - + buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); layout->addWidget(buttonBox); - + setLayout(layout); setWindowTitle(tr("Open")); } From 52d0f0b750ecca5b72892a6e815a1332299594fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 19:44:00 +0100 Subject: [PATCH 0365/1483] Fixed OpAddItem, OpRemoveItem --- apps/openmw/mwscript/containerextensions.cpp | 84 +++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 68ae1b516f..81639b5be9 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -21,6 +21,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/player.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -47,6 +48,10 @@ namespace MWScript if (count<0) throw std::runtime_error ("second argument for AddItem must be non-negative"); + // no-op + if (count == 0) + return; + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item); ref.getPtr().getRefData().setCount (count); @@ -61,26 +66,25 @@ namespace MWScript MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); - // The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory - std::string msgBox; - std::string itemName = MWWorld::Class::get(ref.getPtr()).getName(ref.getPtr()); - if (count == 1) + // Spawn a messagebox (only for items added to player's inventory) + if (ptr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer()) { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); - std::stringstream temp; - temp << boost::format(msgBox) % itemName; - msgBox = temp.str(); - } - else - { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); - std::stringstream temp; - temp << boost::format(msgBox) % (count) % itemName; - msgBox = temp.str(); - } + // The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory + std::string msgBox; + std::string itemName = MWWorld::Class::get(ref.getPtr()).getName(ref.getPtr()); + if (count == 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); + msgBox = boost::str(boost::format(msgBox) % itemName); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); + msgBox = boost::str(boost::format(msgBox) % count % itemName); + } - if(count > 0) MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + } } }; @@ -122,13 +126,19 @@ namespace MWScript Interpreter::Type_Integer count = runtime[0].mInteger; runtime.pop(); - + if (count<0) throw std::runtime_error ("second argument for RemoveItem must be non-negative"); + // no-op + if (count == 0) + return; + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); std::string itemName = ""; + + // originalCount holds the total number of items to remove, count holds the remaining number of items to remove Interpreter::Type_Integer originalCount = count; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; @@ -151,28 +161,26 @@ namespace MWScript } } - // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory - std::string msgBox; - if(originalCount - count > 1) + // Spawn a messagebox (only for items added to player's inventory) + if (ptr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer()) { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); - std::stringstream temp; - temp << boost::format(msgBox) % (originalCount - count) % itemName; - msgBox = temp.str(); - } - else - { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); - std::stringstream temp; - temp << boost::format(msgBox) % itemName; - msgBox = temp.str(); - } - - if(originalCount - count > 0) - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory + std::string msgBox; + int numRemoved = (originalCount - count); + if(numRemoved > 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); + msgBox = boost::str (boost::format(msgBox) % numRemoved % itemName); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); + msgBox = boost::str (boost::format(msgBox) % itemName); + } - // To be fully compatible with original Morrowind, we would need to check if - // count is >= 0 here and throw an exception. But let's be tollerant instead. + if (numRemoved > 0) + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + } } }; From 475f4f9311d1d13348174130711dee02978c5f14 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Feb 2013 20:03:39 +0100 Subject: [PATCH 0366/1483] implicitly add Tribunal/Bloodmoon GMSTs to base, if present neither in base nor in modified --- apps/opencs/model/doc/document.cpp | 129 +++++++++++++++++++++++++++++ apps/opencs/model/doc/document.hpp | 9 ++ apps/opencs/model/world/data.cpp | 10 +++ apps/opencs/model/world/data.hpp | 4 + 4 files changed, 152 insertions(+) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 796135c3ff..e8d3a4eef3 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -18,6 +18,135 @@ void CSMDoc::Document::load (const std::vector::const_i if (lastAsModified) getData().loadFile (*end2, false); + + addOptionalGmsts(); +} + +void CSMDoc::Document::addOptionalGmsts() +{ + static const char *sFloats[] = + { + "fCombatDistanceWerewolfMod", + "fFleeDistance", + "fWereWolfAcrobatics", + "fWereWolfAgility", + "fWereWolfAlchemy", + "fWereWolfAlteration", + "fWereWolfArmorer", + "fWereWolfAthletics", + "fWereWolfAxe", + "fWereWolfBlock", + "fWereWolfBluntWeapon", + "fWereWolfConjuration", + "fWereWolfDestruction", + "fWereWolfEnchant", + "fWereWolfEndurance", + "fWereWolfFatigue", + "fWereWolfHandtoHand", + "fWereWolfHealth", + "fWereWolfHeavyArmor", + "fWereWolfIllusion", + "fWereWolfIntellegence", + "fWereWolfLightArmor", + "fWereWolfLongBlade", + "fWereWolfLuck", + "fWereWolfMagicka", + "fWereWolfMarksman", + "fWereWolfMediumArmor", + "fWereWolfMerchantile", + "fWereWolfMysticism", + "fWereWolfPersonality", + "fWereWolfRestoration", + "fWereWolfRunMult", + "fWereWolfSecurity", + "fWereWolfShortBlade", + "fWereWolfSilverWeaponDamageMult", + "fWereWolfSneak", + "fWereWolfSpear", + "fWereWolfSpeechcraft", + "fWereWolfSpeed", + "fWereWolfStrength", + "fWereWolfUnarmored", + "fWereWolfWillPower", + 0 + }; + + static const char *sIntegers[] = + { + "iWereWolfBounty", + "iWereWolfFightMod", + "iWereWolfFleeMod", + "iWereWolfLevelToAttack", + 0 + }; + + static const char *sStrings[] = + { + "sCompanionShare", + "sCompanionWarningButtonOne", + "sCompanionWarningButtonTwo", + "sCompanionWarningMessage", + "sDeleteNote", + "sEditNote", + "sEffectSummonCreature01", + "sEffectSummonCreature02", + "sEffectSummonCreature03", + "sEffectSummonCreature04", + "sEffectSummonCreature05", + "sEffectSummonFabricant", + "sLevitateDisabled", + "sMagicCreature01ID", + "sMagicCreature02ID", + "sMagicCreature03ID", + "sMagicCreature04ID", + "sMagicCreature05ID", + "sMagicFabricantID", + "sMaxSale", + "sProfitValue", + "sTeleportDisabled", + "sWerewolfAlarmMessage", + "sWerewolfPopup", + "sWerewolfRefusal", + "sWerewolfRestMessage", + 0 + }; + + for (int i=0; sFloats[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sFloats[i]; + gmst.mF = 0; + gmst.mType = ESM::VT_Float; + addOptionalGmst (gmst); + } + + for (int i=0; sIntegers[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sIntegers[i]; + gmst.mI = 0; + gmst.mType = ESM::VT_Long; + addOptionalGmst (gmst); + } + + for (int i=0; sStrings[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sStrings[i]; + gmst.mType = ESM::VT_String; + addOptionalGmst (gmst); + } +} + +void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) +{ + if (getData().getGmsts().searchId (gmst.mId)==-1) + { + CSMWorld::Record record; + record.mBase = gmst; + record.mState = CSMWorld::RecordBase::State_BaseOnly; + getData().getGmsts().appendRecord (record); + } } void CSMDoc::Document::createBase() diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 0162681bcb..413e840d37 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -17,6 +17,11 @@ class QAbstractItemModel; +namespace ESM +{ + struct GameSetting; +} + namespace CSMDoc { class Document : public QObject @@ -46,6 +51,10 @@ namespace CSMDoc void createBase(); + void addOptionalGmsts(); + + void addOptionalGmst (const ESM::GameSetting& gmst); + public: Document (const std::vector& files, bool new_); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 92bd2bdb04..c59763f512 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -54,6 +54,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getGlobals() return mGlobals; } +const CSMWorld::IdCollection& CSMWorld::Data::getGmsts() const +{ + return mGmsts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getGmsts() +{ + return mGmsts; +} + QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 519817a3b4..3745346511 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -40,6 +40,10 @@ namespace CSMWorld IdCollection& getGlobals(); + const IdCollection& getGmsts() const; + + IdCollection& getGmsts(); + QAbstractTableModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// From b52df83d8461978478df3899fd537590e65baabd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 20:23:22 +0100 Subject: [PATCH 0367/1483] Pressing Enter should skip _one_ message box, not skip all message boxes until the key is released again --- apps/openmw/mwinput/inputmanagerimp.cpp | 17 +++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 2 -- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index dc4c020d6c..f1f88b9aec 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -51,7 +51,6 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) - , mEnterPressed(false) { Ogre::RenderWindow* window = ogre.getWindow (); size_t windowHnd; @@ -240,10 +239,6 @@ namespace MWInput void InputManager::update(float dt, bool loading) { - // Pressing enter when a messagebox is prompting for "ok" will activate the ok button - if(mEnterPressed && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox) - MWBase::Environment::get().getWindowManager()->enterPressed(); - // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); @@ -431,8 +426,13 @@ namespace MWInput bool InputManager::keyPressed( const OIS::KeyEvent &arg ) { - if(arg.key == OIS::KC_RETURN && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console) - mEnterPressed = true; + if(arg.key == OIS::KC_RETURN + && MWBase::Environment::get().getWindowManager()->isGuiMode() + && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) + { + // Pressing enter when a messagebox is prompting for "ok" will activate the ok button + MWBase::Environment::get().getWindowManager()->enterPressed(); + } mInputCtrl->keyPressed (arg); unsigned int text = arg.text; @@ -450,9 +450,6 @@ namespace MWInput bool InputManager::keyReleased( const OIS::KeyEvent &arg ) { - if(arg.key == OIS::KC_RETURN) - mEnterPressed = false; - mInputCtrl->keyReleased (arg); MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key)); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index c7ba7b7565..9deed1f285 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -151,8 +151,6 @@ namespace MWInput std::map mControlSwitch; - bool mEnterPressed; - private: void adjustMouseRegion(int width, int height); From 42883ec64bdfbabb32735757230ad79790bc4ed7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 Feb 2013 02:33:53 +0100 Subject: [PATCH 0368/1483] cleanup --- apps/openmw/engine.cpp | 1 - apps/openmw/mwrender/localmap.cpp | 2 - apps/openmw/mwrender/renderingmanager.cpp | 21 ------ apps/openmw/mwrender/renderingmanager.hpp | 2 - apps/openmw/mwrender/water.cpp | 20 ----- apps/openmw/mwrender/water.hpp | 2 - files/CMakeLists.txt | 7 -- files/gbuffer/gbuffer.compositor | 91 ----------------------- files/materials/atmosphere.shader | 9 --- files/materials/clouds.shader | 9 --- files/materials/moon.shader | 10 --- files/materials/objects.shader | 20 +---- files/materials/openmw.configuration | 2 - files/materials/quad.mat | 13 ---- files/materials/quad.shaderset | 16 ---- files/materials/quad2.shader | 23 ------ files/materials/stars.shader | 10 --- files/materials/sun.shader | 10 --- files/materials/terrain.shader | 12 +-- files/materials/water.shader | 13 +--- 20 files changed, 6 insertions(+), 287 deletions(-) delete mode 100644 files/gbuffer/gbuffer.compositor delete mode 100644 files/materials/quad2.shader diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 340e1d3810..d65a5a78c2 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -319,7 +319,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); - addResourcesDirectory(mResDir / "gbuffer"); addResourcesDirectory(mResDir / "shadows"); addZipResource(mResDir / "mygui" / "Obliviontt.zip"); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index e0b7d9a119..de36dcbbf7 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -236,8 +236,6 @@ void LocalMap::render(const float x, const float y, vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0, 0, 0)); vp->setVisibilityMask(RV_Map); - - // use fallback techniques without shadows and without mrt vp->setMaterialScheme("local_map"); rtt->update(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fe8f3e99bf..6c6c474179 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -126,7 +126,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); - sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("fog", "true"); sh::Factory::getInstance ().setGlobalSetting ("lighting", "true"); sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); @@ -690,11 +689,6 @@ void RenderingManager::enableLights(bool sun) sunEnable(sun); } -const bool RenderingManager::useMRT() -{ - return Settings::Manager::getBool("shader", "Water"); -} - Shadows* RenderingManager::getShadows() { return mShadows; @@ -795,7 +789,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec else if (it->second == "shader" && it->first == "Water") { applyCompositors(); - sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); rebuild = true; mRendering.getViewport ()->setClearEveryFrame (true); @@ -873,7 +866,6 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw) mRendering.adjustViewport(); mCompositors->recreate(); - mWater->assignTextures(); mVideoPlayer->setResolution (rw->getWidth(), rw->getHeight()); @@ -897,19 +889,6 @@ bool RenderingManager::waterShaderSupported() void RenderingManager::applyCompositors() { - mCompositors->removeAll(); - if (useMRT()) - { - /* - mCompositors->addCompositor("gbuffer", 0); - mCompositors->setCompositorEnabled("gbuffer", true); - mCompositors->addCompositor("gbufferFinalizer", 2); - mCompositors->setCompositorEnabled("gbufferFinalizer", true); - */ - } - - //if (mWater) - //mWater->assignTextures(); } void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 71ac742c2a..e42c6e06fb 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -104,8 +104,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void removeWater(); - static const bool useMRT(); - void preCellChange (MWWorld::CellStore* store); ///< this event is fired immediately before changing cell diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b006059a9d..f71431a27c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -93,7 +93,6 @@ PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* s vp->setOverlaysEnabled(false); vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setShadowsEnabled(false); - // use fallback techniques without shadows and without mrt vp->setMaterialScheme("water_reflection"); mRenderTarget->addListener(this); mRenderTarget->setActive(true); @@ -232,8 +231,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel underwaterDome->setMaterialName("Underwater_Dome"); */ - assignTextures(); - setHeight(mTop); sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); @@ -362,22 +359,6 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); } -void Water::assignTextures() -{ - if (Settings::Manager::getBool("shader", "Water")) - { -/* - CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mRendering->getViewport())->getCompositor("gbuffer"); - - TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); - sh::Factory::getInstance ().setTextureAlias ("WaterRefraction", colorTexture->getName()); - - TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1); - sh::Factory::getInstance ().setTextureAlias ("SceneDepth", depthTexture->getName()); - */ - } -} - void Water::setViewportBackground(const ColourValue& bg) { if (mReflection) @@ -483,7 +464,6 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin applyRTT(); applyVisibilityMask(); mWater->setMaterial(mMaterial); - assignTextures(); } if (applyVisMask) applyVisibilityMask(); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 9aa18f008a..6100b7cfd2 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -146,8 +146,6 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); - void assignTextures(); - void setViewportBackground(const Ogre::ColourValue& bg); void processChangedSettings(const Settings::CategorySettingVector& settings); diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 65ebc31a2c..c29d917b89 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -6,10 +6,6 @@ set(WATER_FILES circle.png ) -set(GBUFFER_FILES - gbuffer.compositor -) - set(MATERIAL_FILES atmosphere.shader atmosphere.shaderset @@ -22,7 +18,6 @@ set(MATERIAL_FILES objects.shader objects.shaderset openmw.configuration - quad2.shader quad.mat quad.shader quad.shaderset @@ -54,6 +49,4 @@ set(MATERIAL_FILES copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer "${OpenMW_BINARY_DIR}/resources/gbuffer/" "${GBUFFER_FILES}") - copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor deleted file mode 100644 index 0a0675fa00..0000000000 --- a/files/gbuffer/gbuffer.compositor +++ /dev/null @@ -1,91 +0,0 @@ -// Compositor that just controls output to the MRT textures -compositor gbuffer -{ - technique - { - // MRT output. Currently this is a color texture plus a depth texture - texture mrt_output target_width target_height PF_FLOAT16_RGBA PF_FLOAT16_RGBA chain_scope depth_pool 2 - - target mrt_output - { - input none - - pass clear - { - colour_value 0 0 0 1 - } - pass render_quad - { - // this makes sure the depth for background is set to 1 - material openmw_viewport_init - } - pass render_scene - { - // Renders everything except water - first_render_queue 0 - last_render_queue 50 - } - - } - - target_output - { - input none - - pass render_quad - { - material quad - input 0 mrt_output 0 - } - } - } -} - -// Finalizer compositor to render objects that we don't want in the MRT textures (ex. water) -// NB the water has to be rendered in a seperate compositor anyway, because it -// accesses the MRT textures which can't be done while they are still being rendered to. -compositor gbufferFinalizer -{ - technique - { - texture no_mrt_output target_width target_height PF_R8G8B8A8 depth_pool 2 no_fsaa - texture previousscene target_width target_height PF_R8G8B8A8 - - target previousscene - { - input previous - } - target no_mrt_output - { - input none - shadows off - pass clear - { - buffers colour - colour_value 0 0 0 0 - } - pass render_quad - { - material quad_noDepthWrite - input 0 previousscene - } - pass render_scene - { - first_render_queue 51 - last_render_queue 105 - } - } - target_output - { - input none - pass clear - { - } - pass render_quad - { - material quad_noDepthWrite - input 0 no_mrt_output - } - } - } -} diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 16edc78c56..5d71d7c32c 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -1,7 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -19,18 +17,11 @@ SH_BEGIN_PROGRAM shInput(float, alphaFade) -#if MRT - shDeclareMrtOutput(1) -#endif shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) SH_START_PROGRAM { shOutputColour(0) = atmosphereColour * float4(1,1,1,alphaFade); - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index 4b1868fb40..e60026d3bd 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -1,7 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -22,9 +20,6 @@ SH_BEGIN_PROGRAM shInput(float2, UV) shInput(float, alphaFade) -#if MRT - shDeclareMrtOutput(1) -#endif shSampler2D(diffuseMap1) shSampler2D(diffuseMap2) @@ -42,10 +37,6 @@ float4 albedo = shSample(diffuseMap1, scrolledUV) * (1-cloudBlendFactor) + shSample(diffuseMap2, scrolledUV) * cloudBlendFactor; shOutputColour(0) = float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity * alphaFade); - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif diff --git a/files/materials/moon.shader b/files/materials/moon.shader index 02f3d80012..231f60ba06 100644 --- a/files/materials/moon.shader +++ b/files/materials/moon.shader @@ -1,8 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -22,9 +19,6 @@ shSampler2D(diffuseMap) shSampler2D(alphaMap) shInput(float2, UV) -#if MRT - shDeclareMrtOutput(1) -#endif shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) @@ -42,10 +36,6 @@ shOutputColour(0).rgb += (1-tex.a) * shOutputColour(0).a * atmosphereColour.rgb; //fill dark side of moon with atmosphereColour shOutputColour(0).rgb += (1-materialDiffuse.a) * atmosphereColour.rgb; //fade bump -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif - } #endif diff --git a/files/materials/objects.shader b/files/materials/objects.shader index af596b779a..3f5aa418ff 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -2,7 +2,6 @@ #define FOG @shGlobalSettingBool(fog) -#define MRT @shPropertyNotBool(is_transparent) && @shGlobalSettingBool(mrt_output) #define LIGHTING @shGlobalSettingBool(lighting) #define SHADOWS_PSSM LIGHTING && @shGlobalSettingBool(shadows_pssm) @@ -12,7 +11,7 @@ #include "shadows.h" #endif -#if FOG || MRT || SHADOWS_PSSM +#if FOG || SHADOWS_PSSM #define NEED_DEPTH #endif @@ -51,9 +50,9 @@ #if VERTEX_LIGHTING shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) - shUniform(float4, lightPosition[8]) @shAutoConstant(lightPosition, light_position_object_space_array, 8) - shUniform(float4, lightDiffuse[8]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, 8) - shUniform(float4, lightAttenuation[8]) @shAutoConstant(lightAttenuation, light_attenuation_array, 8) + shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_object_space_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) #if !HAS_VERTEXCOLOUR shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) @@ -153,18 +152,11 @@ SH_BEGIN_PROGRAM shSampler2D(diffuseMap) shInput(float2, UV) -#if MRT - shDeclareMrtOutput(1) -#endif #ifdef NEED_DEPTH shInput(float, depthPassthrough) #endif -#if MRT - shUniform(float, far) @shAutoConstant(far, far_clip_distance) -#endif - #if LIGHTING shInput(float3, normalPassthrough) shInput(float3, objSpacePositionPassthrough) @@ -369,10 +361,6 @@ float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); #endif - -#if MRT - shOutputColour(1) = float4(depthPassthrough / far,1,1,1); -#endif } #endif diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index db3693dd66..870c967282 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -3,13 +3,11 @@ configuration water_reflection fog false shadows false shadows_pssm false - mrt_output false } configuration local_map { fog false - mrt_output false shadows false shadows_pssm false simple_water true diff --git a/files/materials/quad.mat b/files/materials/quad.mat index a484d7f28f..77a2c0c340 100644 --- a/files/materials/quad.mat +++ b/files/materials/quad.mat @@ -20,16 +20,3 @@ material quad_noDepthWrite parent quad depth_write off } - -material openmw_viewport_init -{ - pass - { - vertex_program viewport_init_vertex - fragment_program viewport_init_fragment - - depth_write off - depth_check off - scene_blend add - } -} diff --git a/files/materials/quad.shaderset b/files/materials/quad.shaderset index ee230a303d..71fd82da44 100644 --- a/files/materials/quad.shaderset +++ b/files/materials/quad.shaderset @@ -13,19 +13,3 @@ shader_set quad_fragment profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 profiles_hlsl ps_2_0 } - -shader_set viewport_init_vertex -{ - source quad2.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set viewport_init_fragment -{ - source quad2.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/quad2.shader b/files/materials/quad2.shader deleted file mode 100644 index e54d83ef4e..0000000000 --- a/files/materials/quad2.shader +++ /dev/null @@ -1,23 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - } - -#else - - SH_BEGIN_PROGRAM - shUniform(float3, viewportBackground) @shSharedParameter(viewportBackground) - shDeclareMrtOutput(1) - SH_START_PROGRAM - { - shOutputColour(0) = float4(viewportBackground, 1); - shOutputColour(1) = float4(1,1,1,1); - } - -#endif diff --git a/files/materials/stars.shader b/files/materials/stars.shader index 5a55d171e4..fea007424b 100644 --- a/files/materials/stars.shader +++ b/files/materials/stars.shader @@ -1,7 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -22,9 +20,6 @@ #else SH_BEGIN_PROGRAM -#if MRT - shDeclareMrtOutput(1) -#endif shInput(float2, UV) shInput(float, fade) @@ -36,11 +31,6 @@ SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV) * float4(1,1,1, nightFade * fade); - - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif diff --git a/files/materials/sun.shader b/files/materials/sun.shader index 45cd2f24b8..7954f417ce 100644 --- a/files/materials/sun.shader +++ b/files/materials/sun.shader @@ -1,8 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -21,19 +18,12 @@ SH_BEGIN_PROGRAM shSampler2D(diffuseMap) shInput(float2, UV) -#if MRT - shDeclareMrtOutput(1) -#endif shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) //shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) SH_START_PROGRAM { shOutputColour(0) = float4(1,1,1,materialDiffuse.a) * shSample(diffuseMap, UV); - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index d62bb4035e..497463f8ea 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -3,7 +3,6 @@ #define IS_FIRST_PASS 1 #define FOG @shGlobalSettingBool(fog) -#define MRT @shGlobalSettingBool(mrt_output) #define LIGHTING @shGlobalSettingBool(lighting) @@ -18,7 +17,7 @@ #define NUM_LAYERS @shPropertyString(num_layers) -#if MRT || FOG || SHADOWS_PSSM +#if FOG || SHADOWS_PSSM #define NEED_DEPTH 1 #endif @@ -152,11 +151,6 @@ #endif @shPassthroughFragmentInputs - -#if MRT - shDeclareMrtOutput(1) - shUniform(float, far) @shAutoConstant(far, far_clip_distance) -#endif #if LIGHTING @@ -370,10 +364,6 @@ float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); #endif - -#if MRT - shOutputColour(1) = float4(depth / far,1,1,1); -#endif } #endif diff --git a/files/materials/water.shader b/files/materials/water.shader index 400fbefb28..ac6b81240d 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -5,11 +5,7 @@ #if SIMPLE_WATER - // --------------------------------------- SIMPLE WATER --------------------------------------------------- - - - #define MRT @shGlobalSettingBool(mrt_output) - + // --------------------------------------- SIMPLE WATER --------------------------------------------------- #ifdef SH_VERTEX_SHADER @@ -32,9 +28,6 @@ shSampler2D(animatedTexture) shInput(float2, UV) shInput(float, depth) -#if MRT - shDeclareMrtOutput(1) -#endif shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) @@ -47,10 +40,6 @@ float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif From a50ff34774225cd12905a8c7e05740d07b2b5e16 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Feb 2013 09:23:14 +0100 Subject: [PATCH 0369/1483] better default value for string GMSTs --- apps/opencs/model/doc/document.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e8d3a4eef3..da29f6c687 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -133,6 +133,7 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sStrings[i]; + gmst.mStr = ""; gmst.mType = ESM::VT_String; addOptionalGmst (gmst); } From f2948ced2366d126cd8a9870e26a08f9268f974c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 03:07:31 -0800 Subject: [PATCH 0370/1483] Allow diagonal movement --- apps/openmw/mwmechanics/character.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 376092256b..672ab2e9a8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,6 +172,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + Ogre::Vector3 movement(0.0f); + const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); @@ -190,22 +192,28 @@ Ogre::Vector3 CharacterController::update(float duration) setState(isrunning ? (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + // Apply any forward/backward movement manually + movement.y += vec.y * (speed*duration); + } + else if(vec.y != 0.0f) + { + if(vec.y > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + else if(vec.y < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + // Apply any sideways movement manually + movement.x += vec.x * (speed*duration); } - else if(vec.y > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunForward : CharState_RunForward) : - (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); - else if(vec.y < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunBack : CharState_RunBack) : - (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } - Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) { mAnimation->setSpeed(speed); From 627b866744b20524027eca4911e43b9c48e2df25 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 06:29:16 -0800 Subject: [PATCH 0371/1483] Don't try to set a new state when dead --- apps/openmw/mwmechanics/character.cpp | 71 ++++++++++++++------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 672ab2e9a8..27bc62d070 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -174,43 +174,44 @@ Ogre::Vector3 CharacterController::update(float duration) { Ogre::Vector3 movement(0.0f); - const MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::Class &cls = MWWorld::Class::get(mPtr); - const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - const float speed = cls.getSpeed(mPtr); + float speed = 0.0f; + if(!(getState() >= CharState_Death1)) + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Class &cls = MWWorld::Class::get(mPtr); + const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - bool inwater = world->isSwimming(mPtr); - bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); + bool inwater = world->isSwimming(mPtr); + bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); + speed = cls.getSpeed(mPtr); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) - { - if(vec.x > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunRight : CharState_RunRight) : - (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); - else if(vec.x < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : - (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); - // Apply any forward/backward movement manually - movement.y += vec.y * (speed*duration); - } - else if(vec.y != 0.0f) - { - if(vec.y > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunForward : CharState_RunForward) : - (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); - else if(vec.y < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunBack : CharState_RunBack) : - (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); - // Apply any sideways movement manually - movement.x += vec.x * (speed*duration); - } - else - { - if(!(getState() >= CharState_Death1)) + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + { + if(vec.x > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunRight : CharState_RunRight) : + (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); + else if(vec.x < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : + (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + // Apply any forward/backward movement manually + movement.y += vec.y * (speed*duration); + } + else if(vec.y != 0.0f) + { + if(vec.y > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + else if(vec.y < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + // Apply any sideways movement manually + movement.x += vec.x * (speed*duration); + } + else setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } From 178cf2154e1d33d24ddd649387beab13c0696a0d Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 18 Feb 2013 17:59:08 +0100 Subject: [PATCH 0372/1483] Made checking/unchecking work with the new datafiles model --- apps/launcher/datafilespage.cpp | 333 +++++------------- apps/launcher/datafilespage.hpp | 6 +- apps/launcher/settings/gamesettings.cpp | 2 + .../fileorderlist/model/datafilesmodel.cpp | 9 +- 4 files changed, 95 insertions(+), 255 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index fe6c6f424f..ed24f881bd 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -56,12 +56,25 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam , QWidget(parent) { // Models - mMastersModel = new DataFilesModel(this); - mPluginsModel = new DataFilesModel(this); + mDataFilesModel = new DataFilesModel(this); + mDataFilesModel->setObjectName(QString("mDataFilesModel")); + + mMastersProxyModel = new QSortFilterProxyModel(); + mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm")); + mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mMastersProxyModel->setSourceModel(mDataFilesModel); mPluginsProxyModel = new QSortFilterProxyModel(); - mPluginsProxyModel->setDynamicSortFilter(true); - mPluginsProxyModel->setSourceModel(mPluginsModel); + mPluginsProxyModel->setObjectName(QString("mPluginsProxyModel")); + mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); + mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mPluginsProxyModel->setSourceModel(mDataFilesModel); + + mFilterProxyModel = new QSortFilterProxyModel(); + mFilterProxyModel->setObjectName(QString("mFilterProxyModel")); + + mFilterProxyModel->setDynamicSortFilter(true); + mFilterProxyModel->setSourceModel(mPluginsProxyModel); // Filter toolbar QLabel *filterLabel = new QLabel(tr("&Filter:"), this); @@ -86,7 +99,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam unsigned int height = checkBox.sizeHint().height() + 4; mMastersTable = new QTableView(this); - mMastersTable->setModel(mMastersModel); + mMastersTable->setModel(mMastersProxyModel); mMastersTable->setObjectName("MastersTable"); mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection); @@ -109,7 +122,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersTable->setColumnHidden(8, true); mPluginsTable = new QTableView(this); - mPluginsTable->setModel(mPluginsProxyModel); + mPluginsTable->setModel(mFilterProxyModel); mPluginsTable->setObjectName("PluginsTable"); mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -172,7 +185,14 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); + + connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + + connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); + connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); @@ -219,69 +239,20 @@ void DataFilesPage::createActions() mContextMenu->addAction(mUncheckAction); } -void DataFilesPage::readConfig() -{ -// // Don't read the config if no masters are found -// if (mMastersModel->rowCount() < 1) -// return; - -// QString profile = mProfilesComboBox->currentText(); - -// // Make sure we have no groups open -// while (!mLauncherConfig->group().isEmpty()) { -// mLauncherConfig->endGroup(); -// } - -// mLauncherConfig->beginGroup("Profiles"); -// mLauncherConfig->beginGroup(profile); - -// QStringList childKeys = mLauncherConfig->childKeys(); -// QStringList plugins; - -// // Sort the child keys numerical instead of alphabetically -// // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 -// qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); - -// foreach (const QString &key, childKeys) { -// const QString keyValue = mLauncherConfig->value(key).toString(); - -// if (key.startsWith("Plugin")) { -// //QStringList checked = mPluginsModel->checkedItems(); -// EsmFile *file = mPluginsModel->findItem(keyValue); -// QModelIndex index = mPluginsModel->indexFromItem(file); - -// mPluginsModel->setCheckState(index, Qt::Checked); -// // Move the row to the top of te view -// //mPluginsModel->moveRow(index.row(), checked.count()); -// plugins << keyValue; -// } - -// if (key.startsWith("Master")) { -// EsmFile *file = mMastersModel->findItem(keyValue); -// mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); -// } -// } - -// qDebug() << plugins; -} - void DataFilesPage::setupDataFiles() { // Set the encoding to the one found in openmw.cfg or the default - mMastersModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); - mPluginsModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); + mDataFilesModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); QStringList paths = mGameSettings.getDataDirs(); foreach (const QString &path, paths) { - mMastersModel->addMasters(path); - mPluginsModel->addPlugins(path); + mDataFilesModel->addFiles(path); } QString dataLocal = mGameSettings.getDataLocal(); if (!dataLocal.isEmpty()) { - mMastersModel->addMasters(dataLocal); - mPluginsModel->addPlugins(dataLocal); + mDataFilesModel->addFiles(dataLocal); } QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); @@ -313,29 +284,26 @@ void DataFilesPage::loadSettings() qDebug() << mLauncherSettings.values(QString("Profiles/Default"), Qt::MatchStartsWith); - - if (profile.isEmpty()) return; - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); + mDataFilesModel->uncheckAll(); QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly); QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly); qDebug() << "masters to check " << plugins; foreach (const QString &master, masters) { - QModelIndex index = mMastersModel->indexFromItem(mMastersModel->findItem(master)); + QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(master)); if (index.isValid()) - mMastersModel->setCheckState(index, Qt::Checked); + mDataFilesModel->setCheckState(index, Qt::Checked); } foreach (const QString &plugin, plugins) { - QModelIndex index = mPluginsModel->indexFromItem(mPluginsModel->findItem(plugin)); + QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(plugin)); if (index.isValid()) - mPluginsModel->setCheckState(index, Qt::Checked); + mDataFilesModel->setCheckState(index, Qt::Checked); } } @@ -352,178 +320,22 @@ void DataFilesPage::saveSettings() mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); - QStringList items = mMastersModel->checkedItems(); + QStringList items = mDataFilesModel->checkedItems(); - foreach(const QString &master, items) { - qDebug() << "setting " << master; - mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), master); - } + foreach(const QString &item, items) { - items.clear(); - items = mPluginsModel->checkedItems(); + if (item.endsWith(QString(".esm"), Qt::CaseInsensitive)) { + qDebug() << "setting " << item; + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), item); - qDebug() << items.size(); - - foreach(const QString &plugin, items) { - qDebug() << "setting " << plugin; - mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), plugin); + } else if (item.endsWith(QString(".esp"), Qt::CaseInsensitive)) { + qDebug() << "setting " << item; + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), item); + } } } -void DataFilesPage::writeConfig(QString profile) -{ - -// // Don't overwrite the config if no masters are found -// if (mMastersModel->rowCount() < 1) -// return; - -// QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); -// QDir userPath(pathStr); - -// if (!userPath.exists()) { -// if (!userPath.mkpath(pathStr)) { -// QMessageBox msgBox; -// msgBox.setWindowTitle("Error creating OpenMW configuration directory"); -// msgBox.setIcon(QMessageBox::Critical); -// msgBox.setStandardButtons(QMessageBox::Ok); -// msgBox.setText(tr("
Could not create %0

\ -// Please make sure you have the right permissions and try again.
").arg(pathStr)); -// msgBox.exec(); - -// qApp->quit(); -// return; -// } -// } -// // Open the OpenMW config as a QFile -// QFile file(pathStr.append("openmw.cfg")); - -// if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { -// // File cannot be opened or created -// QMessageBox msgBox; -// msgBox.setWindowTitle("Error writing OpenMW configuration file"); -// msgBox.setIcon(QMessageBox::Critical); -// msgBox.setStandardButtons(QMessageBox::Ok); -// msgBox.setText(tr("
Could not open or create %0

\ -// Please make sure you have the right permissions and try again.
").arg(file.fileName())); -// msgBox.exec(); - -// qApp->quit(); -// return; -// } - -// QTextStream in(&file); -// QByteArray buffer; - -// // Remove all previous entries from config -// while (!in.atEnd()) { -// QString line = in.readLine(); -// if (!line.startsWith("master") && -// !line.startsWith("plugin") && -// !line.startsWith("data") && -// !line.startsWith("data-local")) -// { -// buffer += line += "\n"; -// } -// } - -// file.close(); - -// // Now we write back the other config entries -// if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { -// QMessageBox msgBox; -// msgBox.setWindowTitle("Error writing OpenMW configuration file"); -// msgBox.setIcon(QMessageBox::Critical); -// msgBox.setStandardButtons(QMessageBox::Ok); -// msgBox.setText(tr("
Could not write to %0

\ -// Please make sure you have the right permissions and try again.
").arg(file.fileName())); -// msgBox.exec(); - -// qApp->quit(); -// return; -// } - -// if (!buffer.isEmpty()) { -// file.write(buffer); -// } - -// QTextStream gameConfig(&file); - - -// QString path; - -// // data= directories -// for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { -// path = QString::fromStdString(it->string()); -// path.remove(QChar('\"')); - -// // Make sure the string is quoted when it contains spaces -// if (path.contains(" ")) { -// gameConfig << "data=\"" << path << "\"" << endl; -// } else { -// gameConfig << "data=" << path << endl; -// } -// } - -// // data-local directory -// if (!mDataLocal.empty()) { -// path = QString::fromStdString(mDataLocal.front().string()); -// path.remove(QChar('\"')); - -// if (path.contains(" ")) { -// gameConfig << "data-local=\"" << path << "\"" << endl; -// } else { -// gameConfig << "data-local=" << path << endl; -// } -// } - - -// if (profile.isEmpty()) -// profile = mProfilesComboBox->currentText(); - -// if (profile.isEmpty()) -// return; - -// // Make sure we have no groups open -// while (!mLauncherConfig->group().isEmpty()) { -// mLauncherConfig->endGroup(); -// } - -// mLauncherConfig->beginGroup("Profiles"); -// mLauncherConfig->setValue("CurrentProfile", profile); - -// // Open the profile-name subgroup -// mLauncherConfig->beginGroup(profile); -// mLauncherConfig->remove(""); // Clear the subgroup - -// // Now write the masters to the configs -// const QStringList masters = mMastersModel->checkedItems(); - -// // We don't use foreach because we need i -// for (int i = 0; i < masters.size(); ++i) { -// const QString currentMaster = masters.at(i); - -// mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster); -// gameConfig << "master=" << currentMaster << endl; - -// } - -// // And finally write all checked plugins -// const QStringList plugins = mPluginsModel->checkedItems(); - -// for (int i = 0; i < plugins.size(); ++i) { -// const QString currentPlugin = plugins.at(i); -// mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin); -// gameConfig << "plugin=" << currentPlugin << endl; -// } - -// file.close(); -// mLauncherConfig->endGroup(); -// mLauncherConfig->endGroup(); -// mLauncherConfig->sync(); -} - - void DataFilesPage::newProfile() { if (mNewProfileDialog->exec() == QDialog::Accepted) { @@ -599,7 +411,13 @@ void DataFilesPage::check() if (!index.isValid()) return; - mPluginsModel->setCheckState(index, Qt::Checked); + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); } } @@ -619,13 +437,19 @@ void DataFilesPage::uncheck() if (!index.isValid()) return; - mPluginsModel->setCheckState(index, Qt::Unchecked); + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked); } } void DataFilesPage::refresh() { - mPluginsModel->sort(0); + mDataFilesModel->sort(0); // Refresh the plugins table mPluginsTable->scrollToTop(); @@ -643,28 +467,35 @@ void DataFilesPage::setCheckState(QModelIndex index) if (!object) return; - if (object->objectName() == QLatin1String("PluginsTable")) { - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(index); - (mPluginsModel->checkState(sourceIndex) == Qt::Checked) - ? mPluginsModel->setCheckState(sourceIndex, Qt::Unchecked) - : mPluginsModel->setCheckState(sourceIndex, Qt::Checked); + if (object->objectName() == QLatin1String("PluginsTable")) { + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (sourceIndex.isValid()) { + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); + } } if (object->objectName() == QLatin1String("MastersTable")) { - (mMastersModel->checkState(index) == Qt::Checked) - ? mMastersModel->setCheckState(index, Qt::Unchecked) - : mMastersModel->setCheckState(index, Qt::Checked); + QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); + + if (sourceIndex.isValid()) { + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); + } } return; - } void DataFilesPage::filterChanged(const QString filter) { QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); - mPluginsProxyModel->setFilterRegExp(regExp); + mFilterProxyModel->setFilterRegExp(regExp); } void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) @@ -690,8 +521,7 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre saveSettings(); mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); + mDataFilesModel->uncheckAll(); loadSettings(); } @@ -712,8 +542,7 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre // Remove the profile from the combobox mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); + mDataFilesModel->uncheckAll(); loadSettings(); } @@ -737,7 +566,13 @@ void DataFilesPage::showContextMenu(const QPoint &point) if (!index.isValid()) return; - (mPluginsModel->checkState(index) == Qt::Checked) + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) ? mUncheckAction->setEnabled(true) : mCheckAction->setEnabled(true); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index ef03e4ad47..e6b4194bdc 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -56,10 +56,12 @@ public slots: void refresh(); private: - DataFilesModel *mMastersModel; - DataFilesModel *mPluginsModel; + DataFilesModel *mDataFilesModel; QSortFilterProxyModel *mPluginsProxyModel; + QSortFilterProxyModel *mMastersProxyModel; + + QSortFilterProxyModel *mFilterProxyModel; QTableView *mMastersTable; QTableView *mPluginsTable; diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 5f0fb77bc4..f87937228a 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -155,4 +155,6 @@ bool GameSettings::writeFile(QTextStream &stream) } } + + return true; } diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 09cffad7ac..036394800a 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -204,13 +204,14 @@ bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, in return false; if (role == Qt::CheckStateRole) { - - emit layoutAboutToBeChanged(); - QString name = item(index.row())->fileName(); mCheckStates[name] = static_cast(value.toInt()); - emit layoutChanged(); + // Force a redraw of the view since unchecking one item can affect another + QModelIndex firstIndex = indexFromItem(mFiles.first()); + QModelIndex lastIndex = indexFromItem(mFiles.last()); + + emit dataChanged(firstIndex, lastIndex); return true; } From bcf4f962098a5e48eb3662b045d8692b50cf0eda Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 18 Feb 2013 23:10:50 +0100 Subject: [PATCH 0373/1483] Added writing masters/plugins to openmw.cfg --- apps/launcher/datafilespage.cpp | 21 +++++---------------- apps/launcher/settings/gamesettings.hpp | 12 ++++++++++++ apps/launcher/settings/settingsbase.hpp | 7 +------ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index ed24f881bd..e0ebefa589 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -57,7 +57,6 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam { // Models mDataFilesModel = new DataFilesModel(this); - mDataFilesModel->setObjectName(QString("mDataFilesModel")); mMastersProxyModel = new QSortFilterProxyModel(); mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm")); @@ -65,14 +64,11 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersProxyModel->setSourceModel(mDataFilesModel); mPluginsProxyModel = new QSortFilterProxyModel(); - mPluginsProxyModel->setObjectName(QString("mPluginsProxyModel")); mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); mPluginsProxyModel->setSourceModel(mDataFilesModel); mFilterProxyModel = new QSortFilterProxyModel(); - mFilterProxyModel->setObjectName(QString("mFilterProxyModel")); - mFilterProxyModel->setDynamicSortFilter(true); mFilterProxyModel->setSourceModel(mPluginsProxyModel); @@ -155,7 +151,6 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam QList sizeList; sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt(); sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt(); - qDebug() << sizeList; mSplitter->setSizes(sizeList); @@ -279,20 +274,15 @@ void DataFilesPage::setupDataFiles() void DataFilesPage::loadSettings() { - qDebug() << "load settings"; QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); - qDebug() << mLauncherSettings.values(QString("Profiles/Default"), Qt::MatchStartsWith); - if (profile.isEmpty()) return; - mDataFilesModel->uncheckAll(); QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly); QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly); - qDebug() << "masters to check " << plugins; foreach (const QString &master, masters) { QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(master)); @@ -316,21 +306,23 @@ void DataFilesPage::saveSettings() mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), profile); } - qDebug() << "save settings" << profile; mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); + mGameSettings.remove(QString("master")); + mGameSettings.remove(QString("plugin")); + QStringList items = mDataFilesModel->checkedItems(); foreach(const QString &item, items) { if (item.endsWith(QString(".esm"), Qt::CaseInsensitive)) { - qDebug() << "setting " << item; mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), item); + mGameSettings.setMultiValue(QString("master"), item); } else if (item.endsWith(QString(".esp"), Qt::CaseInsensitive)) { - qDebug() << "setting " << item; mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), item); + mGameSettings.setMultiValue(QString("plugin"), item); } } @@ -500,7 +492,6 @@ void DataFilesPage::filterChanged(const QString filter) void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) { - qDebug() << "Profile is changed from: " << previous << " to " << current; // Prevent the deletion of the default profile if (current == QLatin1String("Default")) { mDeleteProfileAction->setEnabled(false); @@ -527,7 +518,6 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) { - qDebug() << "rename"; if (previous.isEmpty()) return; @@ -577,7 +567,6 @@ void DataFilesPage::showContextMenu(const QPoint &point) : mCheckAction->setEnabled(true); } - // Show menu mContextMenu->exec(globalPos); diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index 717ce6e877..8aac1552da 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -29,6 +29,18 @@ public: mSettings.insert(key, value); } + inline void setMultiValue(const QString &key, const QString &value) + { + QStringList values = mSettings.values(key); + if (!values.contains(value)) + mSettings.insertMulti(key, value); + } + + inline void remove(const QString &key) + { + mSettings.remove(key); + } + inline QStringList getDataDirs() { return mDataDirs; } inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } inline QString getDataLocal() {return mDataLocal; } diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 361884da6f..e70bc0d721 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -32,15 +32,10 @@ public: inline void setMultiValue(const QString &key, const QString &value) { QStringList values = mSettings.values(key); - if (!values.contains(value)) { - qDebug() << "inserting " << value; + if (!values.contains(value)) mSettings.insertMulti(key, value); - } else { - qDebug() << "not inserting " << value; - } } - inline void remove(const QString &key) { mSettings.remove(key); From 6cceb04adf93e3328c478127a635d13b3b605e93 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Feb 2013 03:08:00 +0100 Subject: [PATCH 0374/1483] When a custom near clip plane is used, we need to fix up a second viewproj matrix manually to get proper depth values in the vertex shader. This fixes fog on reflections. --- apps/openmw/mwrender/refraction.cpp | 11 +++++++- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 6 +++++ files/materials/objects.shader | 33 +++++++++++++++++++++-- files/materials/openmw.configuration | 7 ++++- files/materials/terrain.shader | 24 +++++++++++++++++ 6 files changed, 79 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index a924be7d74..67fe9e3405 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "renderconst.hpp" namespace MWRender @@ -30,7 +32,7 @@ namespace MWRender vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); - vp->setMaterialScheme("water_reflection"); + vp->setMaterialScheme("water_refraction"); vp->setBackgroundColour (Ogre::ColourValue(0.0078, 0.0576, 0.150)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); @@ -54,6 +56,12 @@ namespace MWRender mCamera->setAspectRatio(mParentCamera->getAspectRatio()); mCamera->setFOVy(mParentCamera->getFOVy()); + // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. + // since all we are interested in is depth, we only need the third row of the matrix. + Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); + sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); + sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); + // enable clip plane here to take advantage of CPU culling for overwater or underwater objects mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); @@ -62,6 +70,7 @@ namespace MWRender void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { + mCamera->disableCustomNearClipPlane (); mRenderActive = false; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6c6c474179..c4f2d99cb4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -140,6 +140,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); + sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); + sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); applyCompositors(); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f71431a27c..a76b0d1d35 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -144,6 +144,12 @@ void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) mSky->setSkyPosition(pos); mCamera->enableReflection(mWaterPlane); + // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. + // since all we are interested in is depth, we only need the third row of the matrix. + Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); + sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); + sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); + // enable clip plane here to take advantage of CPU culling for overwater or underwater objects mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); } diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 3f5aa418ff..fad8c1ac84 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -23,12 +23,21 @@ #define VERTEX_LIGHTING 1 +#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) + #ifdef SH_VERTEX_SHADER // ------------------------------------- VERTEX --------------------------------------- SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + +#if VIEWPROJ_FIX + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) + shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) + shUniform(float4x4, vpMatrix) @shAutoConstant(vpMatrix, viewproj_matrix) +#endif + shVertexInput(float2, uv0) shOutput(float2, UV) shNormalInput(float4) @@ -65,7 +74,6 @@ #if SHADOWS shOutput(float4, lightSpacePos0) shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) #endif #if SHADOWS_PSSM @@ -73,7 +81,9 @@ shOutput(float4, lightSpacePos@shIterator) shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) @shEndForeach - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#if !VIEWPROJ_FIX + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif #endif #if VERTEX_LIGHTING @@ -89,9 +99,28 @@ #endif #ifdef NEED_DEPTH + + +#if VIEWPROJ_FIX + float4x4 vpFixed = vpMatrix; +#if !SH_GLSL + vpFixed[2] = vpRow2Fix; +#else + vpFixed[0][2] = vpRow2Fix.x; + vpFixed[1][2] = vpRow2Fix.y; + vpFixed[2][2] = vpRow2Fix.z; + vpFixed[3][2] = vpRow2Fix.w; +#endif + + float4x4 fixedWVP = shMatrixMult(vpFixed, worldMatrix); + + depthPassthrough = shMatrixMult(fixedWVP, shInputPosition).z; +#else depthPassthrough = shOutputPosition.z; #endif +#endif + #if LIGHTING objSpacePositionPassthrough = shInputPosition.xyz; #endif diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index 870c967282..21ac9416bf 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -1,8 +1,13 @@ configuration water_reflection { - fog false shadows false shadows_pssm false + viewproj_fix true +} + +configuration water_refraction +{ + viewproj_fix true } configuration local_map diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 497463f8ea..b7ee15e8dc 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -23,6 +23,8 @@ #define UNDERWATER @shGlobalSettingBool(underwater_effects) && LIGHTING +#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) + #if NEED_DEPTH @shAllocatePassthrough(1, depth) @@ -51,6 +53,10 @@ shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) shUniform(float4x4, viewProjMatrix) @shAutoConstant(viewProjMatrix, viewproj_matrix) +#if VIEWPROJ_FIX + shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) +#endif + shUniform(float2, lodMorph) @shAutoConstant(lodMorph, custom, 1001) shVertexInput(float2, uv0) @@ -94,7 +100,25 @@ shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); #if NEED_DEPTH +#if VIEWPROJ_FIX + float4x4 vpFixed = viewProjMatrix; +#if !SH_GLSL + vpFixed[2] = vpRow2Fix; +#else + vpFixed[0][2] = vpRow2Fix.x; + vpFixed[1][2] = vpRow2Fix.y; + vpFixed[2][2] = vpRow2Fix.z; + vpFixed[3][2] = vpRow2Fix.w; +#endif + + float4x4 fixedWVP = shMatrixMult(vpFixed, worldMatrix); + + float depth = shMatrixMult(fixedWVP, shInputPosition).z; + @shPassthroughAssign(depth, depth); +#else @shPassthroughAssign(depth, shOutputPosition.z); +#endif + #endif @shPassthroughAssign(UV, uv0); From 427152c518aa9c4ffef873772dcc254a9fb44204 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Feb 2013 03:15:31 +0100 Subject: [PATCH 0375/1483] Disabled ripples until we can properly trigger them from the new character controller. --- apps/openmw/mwrender/water.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index a76b0d1d35..f0680f2085 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -393,10 +393,9 @@ void Water::update(float dt, Ogre::Vector3 player) mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - /// \todo player.y is the scene node position (which is above the head) and not the feet position //if (player.y <= mTop) { - mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); + //mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); From 5d403ebdd34ec1c616c4221b5af04a35261662ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Feb 2013 04:03:24 +0100 Subject: [PATCH 0376/1483] Fix collision debug drawer (tcg) --- apps/openmw/mwworld/worldimp.cpp | 4 ++++ libs/openengine/bullet/BtOgreExtras.h | 2 +- libs/openengine/bullet/physic.cpp | 14 ++++++++------ libs/openengine/bullet/physic.hpp | 9 +++++++++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f2d2e2c008..a80f083b58 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -186,6 +186,8 @@ namespace MWWorld mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine); + mPhysEngine->setSceneManager(renderer.getScene()); + mWeatherManager = new MWWorld::WeatherManager(mRendering); int idx = 0; @@ -892,6 +894,8 @@ namespace MWWorld Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } + // the only purpose this has currently is to update the debug drawer + mPhysEngine->stepSimulation (duration); } bool World::toggleCollisionMode() diff --git a/libs/openengine/bullet/BtOgreExtras.h b/libs/openengine/bullet/BtOgreExtras.h index 423924eda8..b20a3ff984 100644 --- a/libs/openengine/bullet/BtOgreExtras.h +++ b/libs/openengine/bullet/BtOgreExtras.h @@ -207,7 +207,7 @@ public: mLineDrawer->setMaterial("BtOgre/DebugLines"); - mLineDrawer->setVisibilityFlags (1024); + //mLineDrawer->setVisibilityFlags (1024); } ~DebugDrawer() diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7ffe071895..220ba5d515 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -191,10 +191,7 @@ namespace Physic { if(!isDebugCreated) { - Ogre::SceneManagerEnumerator::SceneManagerIterator iter = Ogre::Root::getSingleton().getSceneManagerIterator(); - iter.begin(); - Ogre::SceneManager* scn = iter.getNext(); - Ogre::SceneNode* node = scn->getRootSceneNode()->createChildSceneNode(); + Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); node->pitch(Ogre::Degree(-90)); mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld); dynamicsWorld->setDebugDrawer(mDebugDrawer); @@ -219,6 +216,11 @@ namespace Physic return mDebugActive; } + void PhysicEngine::setSceneManager(Ogre::SceneManager* sceneMgr) + { + mSceneMgr = sceneMgr; + } + PhysicEngine::~PhysicEngine() { HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); @@ -471,7 +473,8 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { - dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + // This isn't needed as there are no dynamic objects at this point + //dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); if(isDebugCreated) { mDebugDrawer->step(); @@ -494,7 +497,6 @@ namespace Physic void PhysicEngine::removeCharacter(const std::string &name) { - //std::cout << "remove"; PhysicActorContainer::iterator it = PhysicActorMap.find(name); if (it != PhysicActorMap.end() ) { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 1a28023a90..559bf032ec 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -24,6 +24,11 @@ namespace BtOgre class DebugDrawer; } +namespace Ogre +{ + class SceneManager; +} + namespace MWWorld { class World; @@ -269,6 +274,8 @@ namespace Physic void getObjectAABB(const std::string &mesh, float scale, btVector3 &min, btVector3 &max); + void setSceneManager(Ogre::SceneManager* sceneMgr); + /** * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). */ @@ -305,6 +312,8 @@ namespace Physic typedef std::map PhysicActorContainer; PhysicActorContainer PhysicActorMap; + Ogre::SceneManager* mSceneMgr; + //debug rendering BtOgre::DebugDrawer* mDebugDrawer; bool isDebugCreated; From 17200cb226a8ea95a940e7093f14170098b80d34 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 20:43:55 -0800 Subject: [PATCH 0377/1483] Don't try to move when there's no speed --- apps/openmw/mwmechanics/character.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 27bc62d070..00a58523d4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -185,7 +185,7 @@ Ogre::Vector3 CharacterController::update(float duration) bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { if(vec.x > 0.0f) setState(isrunning ? @@ -198,7 +198,7 @@ Ogre::Vector3 CharacterController::update(float duration) // Apply any forward/backward movement manually movement.y += vec.y * (speed*duration); } - else if(vec.y != 0.0f) + else if(vec.y != 0.0f && speed > 0.0f) { if(vec.y > 0.0f) setState(isrunning ? From 5a1a0b7338f9c4f8bafb2b65d82c649c95c12a65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 22:39:43 -0800 Subject: [PATCH 0378/1483] Add and use an MWWorld::isFlying method --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 11 +++++++++++ apps/openmw/mwworld/worldimp.hpp | 1 + libs/openengine/bullet/physic.cpp | 5 ----- libs/openengine/bullet/physic.hpp | 6 +++++- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index da670cf23e..cc23e035e8 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -286,6 +286,7 @@ namespace MWBase virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; + virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d135d26838..998b90e19e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -336,7 +336,7 @@ namespace MWClass float moveSpeed; if(normalizedEncumbrance > 1.0f) moveSpeed = 0.0f; - else if(0/*world->isFlying(ptr)*/) + else if(world->isFlying(ptr)) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + 0.0f/*levitationBonus*/); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a80f083b58..1a6630232d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1382,6 +1382,17 @@ namespace MWWorld mRendering->getTriangleBatchCount(triangles, batches); } + bool + World::isFlying(const MWWorld::Ptr &ptr) const + { + RefData &refdata = ptr.getRefData(); + /// \todo check for levitation effects + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + if(physactor && physactor->getCollisionMode()) + return false; + return true; + } + bool World::isSwimming(const MWWorld::Ptr &object) const { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8b9b39617b..d347570fe0 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -314,6 +314,7 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); + virtual bool isFlying(const MWWorld::Ptr &ptr) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 220ba5d515..e5045eee60 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -54,11 +54,6 @@ namespace Physic collisionMode = collision; } - bool PhysicActor::getCollisionMode() - { - return collisionMode; - } - void PhysicActor::setRotation(const Ogre::Quaternion &quat) { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 559bf032ec..8ea9657e67 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -78,7 +78,11 @@ namespace Physic void enableCollisions(bool collision); - bool getCollisionMode(); + bool getCollisionMode() const + { + return collisionMode; + } + /** * This returns the visual position of the PhysicActor (used to position a scenenode). From c694161272e61abecd4c429a59c90b8cc05cc03b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 01:28:02 -0800 Subject: [PATCH 0379/1483] Don't try to step if not on the ground --- apps/openmw/mwworld/physicssystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 058160595d..dc290ec28e 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -156,7 +156,8 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + if(!onground || + !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); resultantDirection.normalise(); From 8255a64bfe9038f0aae9df3925ff3f9e6c7c827d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 02:10:36 -0800 Subject: [PATCH 0380/1483] Handle levitate and swift swim effects --- apps/openmw/mwclass/npc.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 998b90e19e..4a31334adf 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -322,6 +322,8 @@ namespace MWClass { const MWBase::World *world = MWBase::Environment::get().getWorld(); const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); + const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr); float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified()* @@ -330,16 +332,17 @@ namespace MWClass walkSpeed = std::max(0.0f, walkSpeed); if(Npc::getStance(ptr, Sneak, false)) walkSpeed *= fSneakSpeedMultiplier->getFloat(); + float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); float moveSpeed; - if(normalizedEncumbrance > 1.0f) + if(normalizedEncumbrance >= 1.0f) moveSpeed = 0.0f; else if(world->isFlying(ptr)) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + - 0.0f/*levitationBonus*/); + mageffects.get(MWMechanics::EffectKey(10)).mMagnitude/*levitate*/); flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); @@ -350,7 +353,7 @@ namespace MWClass float swimSpeed = walkSpeed; if(Npc::getStance(ptr, Run, false)) swimSpeed = runSpeed; - swimSpeed *= 1.0f + 0.01f * 0.0f/*swiftSwimBonus*/; + swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1)).mMagnitude/*swift swim*/; swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; From a510adc57279f227cfa26af7b45df2921556236c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 02:25:57 -0800 Subject: [PATCH 0381/1483] Allow stepping when not being affected by gravity --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index dc290ec28e..63f9cb949e 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -156,7 +156,7 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(!onground || + if((gravity && !onground) || !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); From 1399a06c76708c438ea4a3f47a59f267be84c7ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:01:33 -0800 Subject: [PATCH 0382/1483] Update animation looping when setting the same state --- apps/openmw/mwmechanics/character.cpp | 4 ++++ apps/openmw/mwrender/animation.cpp | 5 +++++ apps/openmw/mwrender/animation.hpp | 2 ++ 3 files changed, 11 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 00a58523d4..713f1bb3b4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -260,7 +260,11 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) + { + if(mAnimation) + mAnimation->setLooping(loop); return; + } mState = state; if(!mAnimation) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1a606992a2..da91af0051 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,6 +169,11 @@ void Animation::setSpeed(float speed) mAnimSpeedMult = speed / mAnimVelocity; } +void Animation::setLooping(bool loop) +{ + mLooping = loop; +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index fc35c06be6..2f930e9adb 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -76,6 +76,8 @@ public: void setSpeed(float speed); + void setLooping(bool loop); + void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; From 89fabdb3a935a9512df98d91cbe20fabc24332cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:18:15 -0800 Subject: [PATCH 0383/1483] Update the PhysicActor's RigidBody when moving This works, but is less than ideal. As it is now, the rigid body gets updated twice as the position and rotation are set separately. They should instead be updated together. --- apps/openmw/mwworld/physicssystem.cpp | 4 ++++ libs/openengine/bullet/physic.cpp | 7 +++++++ libs/openengine/bullet/physic.hpp | 2 ++ 3 files changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 63f9cb949e..ec867326df 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -414,6 +414,10 @@ namespace MWWorld mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); } } + else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) + { + physact->setPosition(position); + } } void PhysicsSystem::rotateObject (const Ptr& ptr) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e5045eee60..4a1c33fb8e 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -55,6 +55,12 @@ namespace Physic } + void PhysicActor::setPosition(const Ogre::Vector3 &pos) + { + if(pos != getPosition()) + mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); + } + void PhysicActor::setRotation(const Ogre::Quaternion &quat) { if(!quat.equals(getRotation(), Ogre::Radian(0))){ @@ -62,6 +68,7 @@ namespace Physic } } + Ogre::Vector3 PhysicActor::getPosition() { btVector3 vec = mBody->getWorldTransform().getOrigin(); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 8ea9657e67..bd5d3d50aa 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -69,6 +69,8 @@ namespace Physic ~PhysicActor(); + void setPosition(const Ogre::Vector3 &pos); + /** * This adjusts the rotation of a PhysicActor * If we have any problems with this (getting stuck in pmove) we should change it From 5d55b41714dfec738b71f5a0c0988d6021b9cb27 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:59:38 -0800 Subject: [PATCH 0384/1483] Remove a now-unneeded(?) hack --- apps/openmw/mwworld/physicssystem.cpp | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index ec867326df..5552bd7497 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -394,30 +394,13 @@ namespace MWWorld void PhysicsSystem::moveObject (const Ptr& ptr) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); - Ogre::Vector3 position = node->getPosition(); - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - - - if(dynamic_cast(body->getCollisionShape()) == NULL){ - btTransform tr = body->getWorldTransform(); - tr.setOrigin(btVector3(position.x,position.y,position.z)); - body->setWorldTransform(tr); - } - else{ - //For objects that contain a box shape. - //Do any such objects exist? Perhaps animated objects? - mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); - } - } + Ogre::SceneNode *node = ptr.getRefData().getBaseNode(); + const std::string &handle = node->getName(); + const Ogre::Vector3 &position = node->getPosition(); + if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle)) + body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) - { physact->setPosition(position); - } } void PhysicsSystem::rotateObject (const Ptr& ptr) From f8349a04bf95033b8ba4119f460cedb8216c16c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 05:26:58 -0800 Subject: [PATCH 0385/1483] Use the looping portion of the animation to calculate the velocity --- apps/openmw/mwrender/animation.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index da91af0051..d63e302473 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -284,12 +284,32 @@ void Animation::play(const std::string &groupname, const std::string &start, boo if(track && track->getNumKeyFrames() > 1) { - const Ogre::TransformKeyFrame *startkf, *endkf; - startkf = static_cast(track->getKeyFrame(0)); - endkf = static_cast(track->getKeyFrame(track->getNumKeyFrames() - 1)); + float loopstarttime = 0.0f; + float loopstoptime = mCurrentAnim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); + while(keyiter != mCurrentKeys->end()) + { + if(keyiter->second == "loop start") + loopstarttime = keyiter->first; + else if(keyiter->second == "loop stop") + { + loopstoptime = keyiter->first; + break; + } + keyiter++; + } - mAnimVelocity = startkf->getTranslate().distance(endkf->getTranslate()) / - mCurrentAnim->getLength(); + if(loopstoptime > loopstarttime) + { + Ogre::TransformKeyFrame startkf(0, loopstarttime); + Ogre::TransformKeyFrame endkf(0, loopstoptime); + + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + + mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); + } } } From 8196694c08580aece938d644f2f011ad17a08584 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 06:04:25 -0800 Subject: [PATCH 0386/1483] Avoid applying the animation when resetting it --- apps/openmw/mwrender/animation.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d63e302473..3300454231 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -228,8 +228,8 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff); mLastPosition += posdiff; + mAccumRoot->setPosition(-mLastPosition); } return posdiff; } @@ -247,12 +247,24 @@ void Animation::reset(const std::string &marker) mNextKey = mCurrentKeys->begin(); mCurrentTime = 0.0f; } - applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); if(mNonAccumRoot) { - mLastPosition = mNonAccumRoot->getPosition() * mAccumulate; - mAccumRoot->setPosition(-mLastPosition); + const Ogre::NodeAnimationTrack *track = 0; + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track) + { + Ogre::TransformKeyFrame kf(0, mCurrentTime); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); + mLastPosition = kf.getTranslate() * mAccumulate; + } } } From 86f6491bc8e15782e23f369bf1ff6c0453b04f1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 06:38:48 -0800 Subject: [PATCH 0387/1483] Remove unused pmove code --- CMakeLists.txt | 2 - libs/openengine/bullet/physic.cpp | 1 - libs/openengine/bullet/pmove.cpp | 2115 ----------------------------- libs/openengine/bullet/pmove.h | 206 --- libs/openengine/bullet/trace.cpp | 3 - libs/openengine/bullet/trace.h | 4 - 6 files changed, 2331 deletions(-) delete mode 100644 libs/openengine/bullet/pmove.cpp delete mode 100644 libs/openengine/bullet/pmove.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cfd1c7dd39..fac7bb41ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,8 +94,6 @@ set(OENGINE_BULLET ${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.h - ${LIBDIR}/openengine/bullet/pmove.cpp - ${LIBDIR}/openengine/bullet/pmove.h ${LIBDIR}/openengine/bullet/trace.cpp ${LIBDIR}/openengine/bullet/trace.h diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 4a1c33fb8e..5d5749d5d8 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -2,7 +2,6 @@ #include #include #include -#include "pmove.h" #include #include "CMotionState.h" #include "OgreRoot.h" diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp deleted file mode 100644 index 9cd76968a1..0000000000 --- a/libs/openengine/bullet/pmove.cpp +++ /dev/null @@ -1,2115 +0,0 @@ -/* -This source file is a *modified* version of bg_pmove.c from the Quake 3 Arena source code, -which was released under the GNU GPL (v2) in 2005. -Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. -*/ - - -#include "pmove.h" - -//#include "bprintf.h" - -//#include "..\..\ESMParser\ESMParser\CELL.h" - -//#include "GameTime.h" - -//#include "Sound.h" - -//#include "..\..\ESMParser\ESMParser\SNDG.h" -//#include "..\..\ESMParser\ESMParser\SOUN.h" - -#include - -#include "trace.h" - -//SceneInstance* global_lastscene = NULL; - -// Forward declaration: -void PM_AirMove(); - -static playerMove* pm = NULL; - -//extern std::map ExtCellLookup; - -static struct playermoveLocal -{ - playermoveLocal() : frametime(1.0f / 20.0f), groundPlane(true), walking(true), msec(50) - { - forward = Ogre::Vector3(0.0f, 0.0f, 0.0f); - right = Ogre::Vector3(0.0f, 0.0f, 0.0f); - up = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - previous_origin = Ogre::Vector3(0.0f, 0.0f, 0.0f); - previous_velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - } - - traceResults groundTrace; - - //SceneInstance* scene; - - float frametime; // in seconds (usually something like 0.01f) - float impactSpeed; - - Ogre::Vector3 forward; - Ogre::Vector3 right; - Ogre::Vector3 up; - - int msec; - - Ogre::Vector3 previous_origin, previous_velocity; - - int previous_waterlevel; // the waterlevel before this pmove - - bool groundPlane; // if we're standing on a groundplane this frame - - bool walking; - int waterHeight; - bool hasWater; - bool isInterior; - -} pml; - -static inline void PM_ClipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) -{ - float backoff; - //float change; - //int i; - - // backoff = in dot normal - //backoff = DotProduct (in, normal); - backoff = in.dotProduct(normal); - - if ( backoff < 0 ) - backoff *= overbounce; - else - backoff /= overbounce; - - // change = normal * backoff - // out = in - change - /*for ( i=0 ; i<3 ; i++ ) - { - change = normal[i]*backoff; - out[i] = in[i] - change; - - }*/ - float changex = normal.x * backoff; - out.x = in.x - changex; - float changey = normal.y * backoff; - out.y = in.y - changey; - float changez = normal.z * backoff; - out.z = in.z - changez; -} - -float VectorNormalize2( const Ogre::Vector3& v, Ogre::Vector3& out) -{ - float length, ilength; - - length = v.x * v.x+ v.y * v.y + v.z * v.z; - length = sqrt(length); - - if (length) - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) ); -#endif - ilength = 1 / length; - out.x= v.x * ilength; - out.y = v.y * ilength; - out.z = v.z * ilength; - } else - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])==0.0f) && (Q_fabs(v[1])==0.0f) && (Q_fabs(v[2])==0.0f)) ); -#endif - //VectorClear( out ); - out.x = 0; out.y = 0; out.z = 0; - } - - return length; - -} - - -float VectorNormalize(Ogre::Vector3& out) -{ - float length, ilength; - - length = out.x * out.x + out.y * out.y + out.z * out.z; - length = sqrt(length); - - if (length) - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) ); -#endif - ilength = 1 / length; - out.x = out.x * ilength; - out.y = out.y * ilength; - out.z = out.z * ilength; - } - - return length; - -} - -/* -================== -PM_SlideMove - -Returns qtrue if the velocity was clipped in some way -================== -*/ - -bool PM_SlideMove( bool gravity ) -{ - int bumpcount, numbumps; - Ogre::Vector3 dir; - float d; - int numplanes; - Ogre::Vector3 planes[MAX_CLIP_PLANES]; - Ogre::Vector3 primal_velocity; - Ogre::Vector3 clipVelocity; - int i, j, k; - struct traceResults trace; - Ogre::Vector3 end(0,0,0); - float time_left; - float into; - Ogre::Vector3 endVelocity(0,0,0); - Ogre::Vector3 endClipVelocity(0,0,0); - - numbumps = 4; - - // primal_velocity = pm->ps->velocity - //VectorCopy (pm->ps->velocity, primal_velocity); - primal_velocity = pm->ps.velocity; - - if ( gravity ) - { - // endVelocity = pm->ps->velocity - vec3(0, 0, pm->ps->gravity * pml.frametime) - //VectorCopy( pm->ps->velocity, endVelocity ); - endVelocity = pm->ps.velocity; - //endVelocity[2] -= pm->ps->gravity * pml.frametime; - endVelocity.z -= pm->ps.gravity * pml.frametime; - - // pm->ps->velocity = avg(pm->ps->velocity.z, endVelocity.z) - //pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; - pm->ps.velocity.z= (pm->ps.velocity.z + endVelocity.z) * 0.5f; - - //primal_velocity[2] = endVelocity[2]; - primal_velocity.z = endVelocity.z; - - if ( pml.groundPlane ) - // slide along the ground plane - //PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP); - } - - time_left = pml.frametime; - - // never turn against the ground plane - if ( pml.groundPlane ) - { - numplanes = 1; - - // planes[0] = pml.groundTrace.plane.normal - //VectorCopy( pml.groundTrace.plane.normal, planes[0] ); - planes[0] = pml.groundTrace.planenormal; - } else - numplanes = 0; - - // never turn against original velocity - VectorNormalize2( pm->ps.velocity, planes[numplanes] ); - numplanes++; - - for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) - { - - // calculate position we are trying to move to - //VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); - end = pm->ps.origin + pm->ps.velocity * time_left; - - // see if we can make it there - //pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemaskg); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&(end), *(const D3DXVECTOR3* const)&(pm->ps.velocity), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, end, pm->ps.halfExtents, Ogre::Math::DegreesToRadians (pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - if (trace.allsolid) - { - // entity is completely trapped in another solid - //pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - - if (trace.fraction > 0) - // actually covered some distance - //VectorCopy (trace.endpos, pm->ps->origin); - pm->ps.origin = trace.endpos; - - if (trace.fraction == 1) - break; // moved the entire distance - - // save entity for contact8 - //PM_AddTouchEnt( trace.entityNum ); - - time_left -= time_left * trace.fraction; - - if (numplanes >= MAX_CLIP_PLANES) - { - // this shouldn't really happen - //VectorClear( pm->ps->velocity ); - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - - // - // if this is the same plane we hit before, nudge velocity - // out along it, which fixes some epsilon issues with - // non-axial planes - // - for ( i = 0 ; i < numplanes ; i++ ) - { - if (trace.planenormal.dotProduct(planes[i]) > 0.99) //OGRE::VECTOR3 ? - //if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) - { - // pm->ps->velocity += (trace.plane.normal + pm->ps->velocity) - //VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); - pm->ps.velocity = trace.planenormal + pm->ps.velocity; - break; - } - } - - if ( i < numplanes ) - continue; - - //VectorCopy (trace.plane.normal, planes[numplanes]); - planes[numplanes] = trace.planenormal; - numplanes++; - - // - // modify velocity so it parallels all of the clip planes - // - - // find a plane that it enters - for ( i = 0 ; i < numplanes ; i++ ) - { - //into = DotProduct( pm->ps->velocity, planes[i] ); - into = pm->ps.velocity.dotProduct(planes[i]); - if ( into >= 0.1 ) - continue; // move doesn't interact with the plane - - - if(planes[i].x >= .70) - { - pm->ps.velocity.z = 0; - return true; - } - // see how hard we are hitting things - if ( -into > pml.impactSpeed ) - pml.impactSpeed = -into; - - // slide along the plane - //PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, planes[i], clipVelocity, OVERCLIP); - - // slide along the plane - PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); - - // see if there is a second plane that the new move enters - for ( j = 0 ; j < numplanes ; j++ ) - { - if ( j == i ) - continue; - - if (clipVelocity.dotProduct(planes[j]) >= 0.1) - //if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) - continue; // move doesn't interact with the plane - - - - - //pm->ps.velocity = Ogre::Vector3(0,0,0); - //return true; - - - // try clipping the move to the plane - PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); - PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); - - // see if it goes back into the first clip plane - if (clipVelocity.dotProduct(planes[i]) >= 0) - //if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) - continue; - - - // slide the original velocity along the crease - //dProduct (planes[i], planes[j], dir); - dir = planes[i].crossProduct(planes[j]) ; - - //VectorNormalize( dir ); - //D3DXVec3Normalize( (D3DXVECTOR3* const)&dir, (const D3DXVECTOR3* const)&dir); - VectorNormalize(dir); - - //d = DotProduct( dir, pm->ps->velocity ); - d = dir.dotProduct(pm->ps.velocity); - - //VectorScale( dir, d, clipVelocity ); - clipVelocity = dir * d; - - //CrossProduct (planes[i], planes[j], dir); - dir = planes[i].crossProduct(planes[j]) ; - - - //VectorNormalize( dir ); - //D3DXVec3Normalize( (D3DXVECTOR3* const)&dir, (const D3DXVECTOR3* const)&dir); - VectorNormalize(dir); - - //d = DotProduct( dir, endVelocity ); - d = dir.dotProduct(endVelocity); - - //VectorScale( dir, d, endClipVelocity ); - endClipVelocity = dir * d; - - // see if there is a third plane the the new move enters - for ( k = 0 ; k < numplanes ; k++ ) - { - - if ( k == i || k == j ) - continue; - - if (clipVelocity.dotProduct(planes[k]) >= 0.1) - //if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) - continue; // move doesn't interact with the plane - - // stop dead at a tripple plane interaction - //VectorClear( pm->ps->velocity ); - //printf("Stop dead at a triple plane interaction\n"); - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - } - - // if we have fixed all interactions, try another move - //VectorCopy( clipVelocity, pm->ps->velocity ); - pm->ps.velocity = clipVelocity; - - //VectorCopy( endClipVelocity, endVelocity ); - endVelocity = endClipVelocity; - break; - } - } - - if ( gravity ) - //VectorCopy( endVelocity, pm->ps->velocity ); - pm->ps.velocity = endVelocity; - - // don't change velocity if in a timer (FIXME: is this correct?) - if ( pm->ps.pm_time ) - //VectorCopy( primal_velocity, pm->ps->velocity ); - pm->ps.velocity = primal_velocity; - - //return ( (qboolean)(bumpcount != 0) ); - return bumpcount != 0; -} - -/* -================== -PM_StepSlideMove - -================== -*/ -int PM_StepSlideMove( bool gravity ) -{ - Ogre::Vector3 start_o, start_v; - Ogre::Vector3 down_o, down_v; - traceResults trace; -// float down_dist, up_dist; -// vec3_t delta, delta2; - Ogre::Vector3 up, down; - float stepSize; - - //std::cout << "StepSlideMove\n"; - // start_o = pm->ps->origin - //VectorCopy (pm->ps->origin, start_o); - start_o = pm->ps.origin; - - // start_v = pm->ps->velocity - //VectorCopy (pm->ps->velocity, start_v); - start_v = pm->ps.velocity; - - if ( PM_SlideMove( gravity ) == false ) - return 1; // we got exactly where we wanted to go first try - - - // down = start_o - vec3(0, 0, STEPSIZE) - //VectorCopy(start_o, down); - down = start_o; - down.z -= STEPSIZE; - - //pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, start_o, down, , 0, pml.scene); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, down, start_o, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - // up = vec3(0, 0, 1) - //VectorSet(up, 0, 0, 1); - up = Ogre::Vector3(0.0f, 0.0f, 1.0f); - - // never step up when you still have up velocity - //if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || DotProduct(trace.plane.normal, up) < 0.7)) - if (pm->ps.velocity.z > 0 && ( - trace.fraction == 1.0 || trace.planenormal.dotProduct(up) < 0.7 - ) ) - return 2; - - // down_o = pm->ps->origin - //VectorCopy (pm->ps->origin, down_o); - down_o = pm->ps.origin; - - // down_v = pm->ps->velocity - //VectorCopy (pm->ps->velocity, down_v); - down_v = pm->ps.velocity; - - // up = start_o + vec3(0, 0, STEPSIZE) - //VectorCopy (start_o, up); - up = start_o; - //up[2] += STEPSIZE; - up.z += STEPSIZE; - - // test the player position if they were a stepheight higher - //pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&up, D3DXVECTOR3(0.0f, STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, start_o, up, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( trace.allsolid ) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:bend can't step\n", c_pmove); - //bprintf("bend can't step\n"); - return 3; // can't step up - } - - //stepSize = trace.endpos[2] - start_o[2]; - stepSize = trace.endpos.z - start_o.z; - - // try slidemove from this position - //VectorCopy (trace.endpos, pm->ps->origin); // pm->ps->origin = trace.endpos - pm->ps.origin = trace.endpos; - //VectorCopy (start_v, pm->ps->velocity); // pm->ps->velocity = start_v - pm->ps.velocity = start_v; - - PM_SlideMove( gravity ); - - // push down the final amount - - // down = pm->ps->origin - vec3(0, 0, stepSize) - //VectorCopy (pm->ps->origin, down); - down = pm->ps.origin; - //down[2] -= stepSize; - down.z -= stepSize; - - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, down, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( !trace.allsolid ) - //VectorCopy (trace.endpos, pm->ps->origin); - pm->ps.origin = trace.endpos; - - if ( trace.fraction < 1.0 ) - //PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, trace.planenormal, pm->ps.velocity, OVERCLIP); - - { - // use the step move - float delta; - - //delta = pm->ps->origin[2] - start_o[2]; - delta = pm->ps.origin.z - start_o.z; - if ( delta > 2 ) - { - pm->ps.counter = 10; - - /* - if (gravity) - printf("g on: %f ", delta); - else - printf("g off: %f ", delta); - - if ( delta < 7 ) - printf("stepped 3 < x < 7\n"); - //PM_AddEvent( EV_STEP_4 ); - else if ( delta < 11 ) - printf("stepped 7 < x < 11\n"); - //PM_AddEvent( EV_STEP_8 ); - else if ( delta < 15 ) - printf("stepped 11 < x < 15\n"); - //PM_AddEvent( EV_STEP_12 ); - else - printf("stepped 15+\n"); - //PM_AddEvent( EV_STEP_16 ); - */ - } - /*if ( pm->debugLevel ) - Com_Printf("%i:stepped\n", c_pmove);*/ - } - - return 4; -} - -void PM_Friction(void) -{ - - Ogre::Vector3 vec; - float* vel; - float speed, newspeed, control; - float drop; - - vel = &(pm->ps.velocity.x); - - // vec = vel - //VectorCopy( vel, vec ); - vec = pm->ps.velocity; - - if ( pml.walking ) - //vec[2] = 0; // ignore slope movement - vec.z = 0; - - //speed = VectorLength(vec); - speed = vec.length(); - if (speed < 1) - { - vel[0] = 0; - vel[1] = 0; // allow sinking underwater - // FIXME: still have z friction underwater? - //bprintf("Static friction (vec = [%f, %f, %f]) (vec.length = %f)\n", vec.x, vec.y, vec.z, speed); - return; - } - - drop = 0; - - // apply ground friction - if ( pm->ps.waterlevel <= 1 ) - { - if ( pml.walking )//&& !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) - { - // if getting knocked back, no friction - //if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) - { - control = (speed < pm_stopspeed) ? pm_stopspeed : speed; - drop += control * pm_friction * pml.frametime; - } - } - } - - // apply water friction even if just wading - if ( pm->ps.waterlevel ) - drop += speed * pm_waterfriction * pm->ps.waterlevel * pml.frametime; - - // apply flying friction - /*if ( pm->ps->powerups[PW_FLIGHT]) - drop += speed * pm_flightfriction * pml.frametime; - - if ( pm->ps->pm_type == PM_SPECTATOR) - drop += speed * pm_spectatorfriction * pml.frametime;*/ - if (pm->ps.move_type == PM_SPECTATOR) - drop += speed * pm_flightfriction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - - newspeed /= speed; - - // vel *= newspeed - vel[0] = vel[0] * newspeed; - vel[1] = vel[1] * newspeed; - vel[2] = vel[2] * newspeed; -} - -float PM_CmdScale(playerMove::playercmd* const cmd) -{ - int max; - float total; - float scale; - - max = abs( cmd->forwardmove ); - if ( abs( cmd->rightmove ) > max ) - max = abs( cmd->rightmove ); - - if ( abs( cmd->upmove ) > max ) - max = abs( cmd->upmove ); - - if ( !max ) - return 0; - - total = sqrtf( (const float)(cmd->forwardmove * cmd->forwardmove - + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove) ); - scale = (float)pm->ps.speed * max / ( 127.0f * total ); - if(pm->ps.move_type == PM_NOCLIP) - scale *= 10; - - return scale; -} - -static void PM_Accelerate( Ogre::Vector3& wishdir, float wishspeed, float accel ) -{ -// int i; - float addspeed, accelspeed, currentspeed; - - - // currentspeed = pm->ps->velocity dot wishdir - //currentspeed = DotProduct (pm->ps->velocity, wishdir); - currentspeed = pm->ps.velocity.dotProduct(wishdir); - - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - - accelspeed = accel * pml.frametime * wishspeed; - - // Clamp accelspeed at addspeed - if (accelspeed > addspeed) - accelspeed = addspeed; - - // pm->ps->velocity += accelspeed * wishdir - //for (i=0 ; i<3 ; i++) - //pm->ps->velocity[i] += accelspeed * wishdir[i]; - pm->ps.velocity += (wishdir * accelspeed); - //pm->ps.velocity = wishdir * wishspeed; //New, for instant acceleration - -} - -static bool PM_CheckJump(void) -{ - //if ( pm->ps->pm_flags & PMF_RESPAWNED ) - //return qfalse; // don't allow jump until all buttons are up - - if ( pm->cmd.upmove < 10 ) - // not holding jump - return false; - - pm->cmd.upmove = 0; - - // must wait for jump to be released - /*if ( pm->ps->pm_flags & PMF_JUMP_HELD ) - { - // clear upmove so cmdscale doesn't lower running speed - pm->cmd.upmove = 0; - return false; - }*/ - - pml.groundPlane = false; // jumping away - pml.walking = false; - //pm->ps->pm_flags |= PMF_JUMP_HELD; - - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pm->ps.velocity.z = pm->ps.jump_velocity; - pm->ps.bSnap = false; - //PM_AddEvent( EV_JUMP ); - - /*if ( pm->cmd.forwardmove >= 0 ) - { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - }*/ - - return true; -} - -static void PM_WaterMove( playerMove* const pm ) -{ - //int i; - //vec3_t wishvel; - Ogre::Vector3 wishvel; - float wishspeed; - //vec3_t wishdir; - Ogre::Vector3 wishdir; - float scale; - float vel; - - pm->ps.bSnap = false; - - /*if ( PM_CheckWaterJump() ) - { - PM_WaterJumpMove(); - return; - }*/ -#if 0 - // jump = head for surface - if ( pm->cmd.upmove >= 10 ) { - if (pm->ps->velocity[2] > -300) { - if ( pm->watertype == CONTENTS_WATER ) { - pm->ps->velocity[2] = 100; - } else if (pm->watertype == CONTENTS_SLIME) { - pm->ps->velocity[2] = 80; - } else { - pm->ps->velocity[2] = 50; - } - } - } -#endif - PM_Friction (); - - if (pm->cmd.forwardmove || pm->cmd.rightmove) - { - //NEEDS TO BE REWRITTEN FOR OGRE TIME--------------------------------------------------- - /* - static const TimeTicks footstep_duration = GetTimeFreq(); // make each splash last 1.0s - static TimeTicks lastStepTime = 0; - const TimeTicks thisStepTime = GetTimeQPC(); - static bool lastWasLeft = false; - if (thisStepTime > lastStepTime) - { - if (pm->cmd.ducking) - lastStepTime = thisStepTime + footstep_duration * 2; // splashes while ducking are twice as slow - else - lastStepTime = thisStepTime + footstep_duration; - - lastWasLeft = !lastWasLeft; - */ - //-----------------jhooks1 - - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, lastWasLeft ? SNDG::r_swim : SNDG::l_swim); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - //Sound, ignore for now -- jhooks1 - //} - } - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) - { - /*wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = -60; // sink towards bottom - */ - wishvel.x = 0; - wishvel.z = -60; - wishvel.y = 0; - } - else - { - /*for (i=0 ; i<3 ; i++) - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;*/ - wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; - - //wishvel[2] += scale * pm->cmd.upmove; - wishvel.z += pm->cmd.upmove * scale; - } - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - wishspeed = VectorNormalize(wishdir); - - if ( wishspeed > pm->ps.speed * pm_swimScale ) - wishspeed = pm->ps.speed * pm_swimScale; - - PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); - - // make sure we can go up slopes easily under water - //if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) - if (pml.groundPlane && pm->ps.velocity.dotProduct(pml.groundTrace.planenormal) < 0.0f) - { - //vel = VectorLength(pm->ps->velocity); - vel = pm->ps.velocity.length(); - - // slide along the ground plane - //PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP); - - VectorNormalize(pm->ps.velocity); - //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * vel; - } - - PM_SlideMove( false ); -} - -/* -=================== -PM_WalkMove - -=================== -*/ -static void PM_WalkMove( playerMove* const pmove ) -{ -// int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - playerMove::playercmd cmd; - float accelerate; - float vel; - //pm->ps.gravity = 4000; - - //std::cout << "Player is walking\n"; - - if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) - pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) - { - // begin swimming - PM_WaterMove(pmove); - return; - } - - - if ( PM_CheckJump () ) - { - - // jumped away - if ( pm->ps.waterlevel > 1 ) - PM_WaterMove(pmove); - else - PM_AirMove(); - //printf("Jumped away\n"); - return; - } - - // Footsteps time - if (pmove->cmd.forwardmove || pmove->cmd.rightmove) - { - bool step_underwater = false; - //if (pmove->traceObj) - //{ - - - //jhooks1 - Water handling, deal with later - - - - if (pmove->hasWater) - { - if (pmove->hasWater ) - { - const float waterHeight = pmove->waterHeight; - const float waterSoundStepHeight = waterHeight + pm->ps.halfExtents.y; - if (pmove->ps.origin.y < waterSoundStepHeight) - step_underwater = true; - } - } - //} - - /* - static const TimeTicks footstep_duration = GetTimeFreq() / 2; // make each footstep last 500ms - static TimeTicks lastStepTime = 0; - const TimeTicks thisStepTime = GetTimeQPC(); - static bool lastWasLeft = false; - if (thisStepTime > lastStepTime) - { - if (pmove->cmd.ducking) - lastStepTime = thisStepTime + footstep_duration * 2; // footsteps while ducking are twice as slow - else - lastStepTime = thisStepTime + footstep_duration; - - lastWasLeft = !lastWasLeft; - */ - - if (step_underwater) - { - /* - const namestruct ns(lastWasLeft ? "FootWaterRight" : "FootWaterLeft"); - const SOUN* const soun = SOUN::GetSound(ns); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - }*/ - } - else - { - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, lastWasLeft ? SNDG::r_foot : SNDG::l_foot); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - } - } - - - PM_Friction (); - - - //bprintf("vel: (%f, %f, %f)\n", pm->ps.velocity.x, pm->ps.velocity.y, pm->ps.velocity.z); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - //PM_SetMovementDir(); - - // project moves down to flat plane - //pml.forward[2] = 0; - pml.forward.z = 0; - - //pml.right[2] = 0; - pml.right.z = 0; - //std::cout << "Further down" << pm->ps.velocity << "\n"; - - - // project the forward and right directions onto the ground plane - PM_ClipVelocity (pml.forward, pml.groundTrace.planenormal, pml.forward, OVERCLIP ); - PM_ClipVelocity (pml.right, pml.groundTrace.planenormal, pml.right, OVERCLIP ); - //std::cout << "Clip velocity" << pm->ps.velocity << "\n"; - // - - VectorNormalize (pml.forward); - VectorNormalize (pml.right); - //pml.forward = pml.forward.normalise(); - //pml.right = pml.right.normalise(); - //std::cout << "forward2" << pml.forward << "\n"; - //std::cout << "right2" << pml.right << "\n"; - - - // wishvel = (pml.forward * fmove) + (pml.right * smove); - //for ( i = 0 ; i < 3 ; i++ ) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - - - //bprintf("f: (%f, %f, %f), s: (%f, %f, %f)\n", fmove, smove); - - - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - // wishdir = wishvel - //VectorCopy (wishvel, wishdir); - //wishvel = wishdir; - wishdir = wishvel; - - wishspeed = VectorNormalize(wishdir); - //std::cout << "Wishspeed: " << wishspeed << "\n"; - wishspeed *= scale; - //std::cout << "Wishspeed scaled:" << wishspeed << "\n"; - - // clamp the speed lower if ducking - if ( pm->cmd.ducking ) - if ( wishspeed > pm->ps.speed * pm_duckScale ) - wishspeed = pm->ps.speed * pm_duckScale; - - // clamp the speed lower if wading or walking on the bottom - if ( pm->ps.waterlevel ) - { - float waterScale; - - waterScale = pm->ps.waterlevel / 3.0f; - waterScale = 1.0f - ( 1.0f - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps.speed * waterScale ) - wishspeed = pm->ps.speed * waterScale; - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - //if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - //accelerate = pm_airaccelerate; - //else - accelerate = pm_accelerate; - - - PM_Accelerate (wishdir, wishspeed, accelerate); - //std::cout << "Velocityafter: " << pm->ps.velocity << "\n"; - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - //if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - //pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - //else - //{ - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - //} - - //vel = VectorLength(pm->ps->velocity); - vel = pm->ps.velocity.length(); - //std::cout << "The length" << vel << "\n"; - - // slide along the ground plane - PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, - pm->ps.velocity, OVERCLIP ); - //std::cout << "Velocity clipped" << pm->ps.velocity << "\n"; - - // don't decrease velocity when going up or down a slope - VectorNormalize(pm->ps.velocity); - //pm->ps.velocity = pm->ps.velocity.normalise(); - - //std::cout << "Final:" << pm->ps.velocity << "\n"; - //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * vel; - - // don't do anything if standing still - //if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) - if (!pm->ps.velocity.x && !pm->ps.velocity.z) - return; - - PM_StepSlideMove( false ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - - -} - -void PM_UpdateViewAngles( playerMove::playerStruct* const ps, playerMove::playercmd* const cmd ) -{ - short temp; - int i; - - //while(1); - - //if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) - //return; // no view changes at all - - //if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) - //return; // no view changes at all - - // circularly clamp the angles with deltas - //bprintf("View angles: %i, %i, %i\n", cmd->angles[0], cmd->angles[1], cmd->angles[2]); - for (i = 0 ; i < 3 ; i++) - { - temp = cmd->angles[i];// + ps->delta_angles[i]; - //if ( i == PITCH ) - { - // don't let the player look up or down more than 90 degrees - /*if ( temp > 16000 ) - { - ps->delta_angles[i] = 16000 - cmd->angles[i]; - temp = 16000; - } - else if ( temp < -16000 ) - { - ps->delta_angles[i] = -16000 - cmd->angles[i]; - temp = -16000; - }*/ - } - (&(ps->viewangles.x) )[i] = SHORT2ANGLE(temp); - //cmd->angles[i] += ps->delta_angles[i]; - } - //ps->delta_angles[0] = ps->delta_angles[1] = ps->delta_angles[2] = 0; - -} - -void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) -{ - float angle; - static float sr, sp, sy, cr, cp, cy; - // static to help MS compiler fp bugs - - //angle = angles[YAW] * (M_PI*2 / 360); - angle = angles.x * (M_PI * 2.0f / 360.0f); - sp = sinf(angle); - cp = cosf(angle); - - //angle = angles[PITCH] * (M_PI*2 / 360); - angle = angles.y * (-M_PI * 2.0f / 360.0f); - sy = sinf(angle); - cy = cosf(angle); - - //angle = angles[ROLL] * (M_PI*2 / 360); - angle = angles.z * (M_PI * 2.0f / 360.0f); - sr = sinf(angle); - cr = cosf(angle); - - if (forward) - { - forward->x = cp * cy; - forward->y = cp * sy; - forward->z = -sp; - } - if (right) - { - right->x = (-1 * sr * sp * cy + -1 * cr * -sy); - right->y = (-1 * sr * sp * sy + -1 * cr * cy); - right->z = 0; - } - if (up) - { - up->x =(cr * sp * cy + -sr * -sy); - up->y=(cr * sp * sy + -sr * cy); - up->z = cr * cp; - } - -} - -void PM_GroundTraceMissed() -{ - traceResults trace; - Ogre::Vector3 point; - //We should not have significant upwards velocity when in the air, unless we jumped. - //This code protects against flying into the air when moving at high speeds. - //Z velocity is set to 50, instead of 0, to help move up certain steps. - - //std::cout << "Ground trace missed\n"; - // we just transitioned into freefall - //if ( pm->debugLevel ) - //Com_Printf("%i:lift\n", c_pmove); - - // if they aren't in a jumping animation and the ground is a ways away, force into it - // if we didn't do the trace, the player would be backflipping down staircases - //VectorCopy( pm->ps->origin, point ); - point = pm->ps.origin; - //point[2] -= 64; - point.z -= 32; - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -64.0f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - //It hit the ground below - if ( trace.fraction < 1.0 && pm->ps.origin.z > trace.endpos.z) - { - pm->ps.origin = trace.endpos; - pml.walking = true; - pml.groundPlane = true; - pm->ps.groundEntityNum = trace.entityNum; - - } - else{ - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - pm->ps.bSnap = false; - } - - -} - -static bool PM_CorrectAllSolid(traceResults* const trace) -{ - int i, j, k; - Ogre::Vector3 point; - - //if ( pm->debugLevel ) - //Com_Printf("%i:allsolid\n", c_pmove); - //bprintf("allsolid\n"); - - // jitter around - for (i = -1; i <= 1; i++) - { - for (j = -1; j <= 1; j++) - { - for (k = -1; k <= 1; k++) - { - //VectorCopy(pm->ps->origin, point); - point = pm->ps.origin; - - /*point[0] += (float) i; - point[1] += (float) j; - point[2] += (float) k;*/ - point += Ogre::Vector3( (const float)i, (const float)j, (const float)k); - - //pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(trace, *(const D3DXVECTOR3* const)&point, *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0, pml.traceObj); - newtrace(trace, point, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - if ( !trace->allsolid ) - { - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25;*/ - point = pm->ps.origin; - point.z -= 0.25f; - - //pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - pml.groundTrace = *trace; - return true; - } - } - } - } - - //pm->ps->groundEntityNum = ENTITYNUM_NONE; - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - - return false; -} - -static void PM_CrashLand( void ) -{ - float delta; - float dist ; - float vel, acc; - float t; - float a, b, c, den; - - // decide which landing animation to use - /*if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) - PM_ForceLegsAnim( LEGS_LANDB ); - else - PM_ForceLegsAnim( LEGS_LAND ); - - pm->ps->legsTimer = TIMER_LAND;*/ - - // calculate the exact velocity on landing - //dist = pm->ps->origin[2] - pml.previous_origin[2]; - - dist = pm->ps.origin.z - pml.previous_origin.z; - - //vel = pml.previous_velocity[2]; - vel = pml.previous_velocity.z; - - //acc = -pm->ps->gravity; - acc = -pm->ps.gravity; - - a = acc / 2; - b = vel; - c = -dist; - - den = b * b - 4 * a * c; - if ( den < 0 ) - return; - - t = (-b - sqrtf( den ) ) / ( 2 * a ); - - delta = vel + t * acc; - delta = delta * delta * 0.0001f; - - // ducking while falling doubles damage - /*if ( pm->ps->pm_flags & PMF_DUCKED ) - delta *= 2;*/ - if (pm->cmd.upmove < -20) - delta *= 2; - - // never take falling damage if completely underwater - if ( pm->ps.waterlevel == 3 ) - return; - - // reduce falling damage if there is standing water - if ( pm->ps.waterlevel == 2 ) - delta *= 0.25; - if ( pm->ps.waterlevel == 1 ) - delta *= 0.5; - - if ( delta < 1 ) - return; -/* - if (delta > 60) - printf("Far crashland: %f\n", delta); - else if (delta > 40) - printf("Medium crashland: %f\n", delta); - else if (delta > 4) - printf("Short crashland: %f\n", delta); -*/ - if (delta > 60) - { - /* - static const namestruct healthDamage("Health Damage"); - const SOUN* const soun = SOUN::GetSound(healthDamage); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - }*/ - } - - if (delta > 3) // We need at least a short crashland to proc the sound effects: - { - bool splashSound = false; - - if (pm->hasWater) - { - - const float waterHeight = pm->waterHeight; - const float waterHeightSplash = waterHeight + pm->ps.halfExtents.y; - if (pm->ps.origin.z < waterHeightSplash) - { - splashSound = true; - } - - } - - - if (splashSound) - { - //Change this later----------------------------------- - /* - const namestruct ns("DefaultLandWater"); - const SOUN* const soun = SOUN::GetSound(ns); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundDatga->GetVolumeFloat() ); - }*/ - } - else - { - //Change this later--------------------------------- - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, SNDG::land); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - } - } - - // create a local entity event to play the sound - - // SURF_NODAMAGE is used for bounce pads where you don't ever - // want to take damage or play a crunch sound - //if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) - { - /*if ( delta > 60 ) - PM_AddEvent( EV_FALL_FAR ); - else if ( delta > 40 ) - { - // this is a pain grunt, so don't play it if dead - if ( pm->ps->stats[STAT_HEALTH] > 0 ) - PM_AddEvent( EV_FALL_MEDIUM ); - } - else if ( delta > 7 ) - PM_AddEvent( EV_FALL_SHORT ); - else - PM_AddEvent( PM_FootstepForSurface() );*/ - } - - // start footstep cycle over - //pm->ps->bobCycle = 0; -} - -static void PM_GroundTrace( void ) -{ - Ogre::Vector3 point; - traceResults trace; - - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25;*/ - point = pm->ps.origin; - point.z -= 0.25f; - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - pml.groundTrace = trace; - - // do something corrective if the trace starts in a solid... - if ( trace.allsolid ) { - //std::cout << "ALL SOLID\n"; - if ( !PM_CorrectAllSolid(&trace) ){ - //std::cout << "Returning after correct all solid\n"; - return; - } - } - // if the trace didn't hit anything, we are in free fall - if ( trace.fraction == 1.0) - { - if(pm->ps.velocity.z > 50.0f && pm->ps.bSnap && pm->ps.speed > 1000.0f) - pm->ps.velocity.z = 50.0f; - if(pm->ps.snappingImplemented){ - if(pm->ps.bSnap && pm->ps.counter <= 0) - PM_GroundTraceMissed(); - } - - - - return; - } - else - { - //It hit something, so we are on the ground - pm->ps.bSnap = true; - - } - // check if getting thrown off the ground - //if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) - if (pm->ps.velocity.z > 0 && pm->ps.velocity.dotProduct(trace.planenormal) > 10.0f ) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:kickoff\n", c_pmove); - - // go into jump animation - /*if ( pm->cmd.forwardmove >= 0 ) - { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - }*/ - if(!pm->ps.bSnap){ - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - } - else - { - pml.groundPlane = true; - pml.walking = true; - } - return; - } - - - - - // slopes that are too steep will not be considered onground - //if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) - //std::cout << "MinWalkNormal" << trace.planenormal.z; - if (trace.planenormal.z < MIN_WALK_NORMAL) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:steep\n", c_pmove); - - // FIXME: if they can't slide down the slope, let them - // walk (sharp crevices) - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = true; - pml.walking = false; - return; - } - - pml.groundPlane = true; - pml.walking = true; - - // hitting solid ground will end a waterjump - /*if (pm->ps.pm_flags & PMF_TIME_WATERJUMP) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - }*/ - - if ( pm->ps.groundEntityNum == ENTITYNUM_NONE ) - { - // just hit the ground - /*if ( pm->debugLevel ) - Com_Printf("%i:Land\n", c_pmove);*/ - //bprintf("Land\n"); - - PM_CrashLand(); - - // don't do landing time if we were just going down a slope - //if ( pml.previous_velocity[2] < -200 ) - if (pml.previous_velocity.z < -200) - { - // don't allow another jump for a little while - //pm->ps->pm_flags |= PMF_TIME_LAND; - pm->ps.pm_time = 250; - } - } - - pm->ps.groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - //PM_AddTouchEnt( trace.entityNum ); -} - -void PM_AirMove() -{ - //int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - playerMove::playercmd cmd; - //pm->ps.gravity = 800; - PM_Friction(); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - // set the movementDir so clients can rotate the legs for strafing - //PM_SetMovementDir(); - - // project moves down to flat plane - //pml.forward[2] = 0; - pml.forward.z = 0; //Z or Y? - //pml.right[2] = 0; - pml.right.z = 0; - //VectorNormalize (pml.forward); - VectorNormalize(pml.forward); - VectorNormalize(pml.right); - //VectorNormalize (pml.right); - - //for ( i = 0 ; i < 2 ; i++ ) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - - //wishvel[2] = 0; - wishvel.z = 0; - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - //wishspeed = VectorNormalize(wishdir); - wishspeed = VectorNormalize(wishdir); - - wishspeed *= scale; - - // not on ground, so little effect on velocity - PM_Accelerate (wishdir, wishspeed, pm_airaccelerate); - - // we may have a ground plane that is very steep, even - // though we don't have a groundentity - // slide along the steep plane - if ( pml.groundPlane ) - PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP ); - -/*#if 0 - //ZOID: If we are on the grapple, try stair-stepping - //this allows a player to use the grapple to pull himself - //over a ledge - if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - PM_StepSlideMove ( qtrue ); - else - PM_SlideMove ( qtrue ); -#endif*/ - //std::cout << "Moving in the air" << pm->ps.velocity << "\n"; - - /*bprintf("%i ", */PM_StepSlideMove ( true )/* )*/; - - -} - -static void PM_NoclipMove( void ) -{ - float speed, drop, friction, control, newspeed; -// int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - - //pm->ps->viewheight = DEFAULT_VIEWHEIGHT; - - // friction - - //speed = VectorLength (pm->ps->velocity); - speed = pm->ps.velocity.length(); - if (speed < 1) - //VectorCopy (vec3_origin, pm->ps->velocity); - pm->ps.velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - else - { - drop = 0; - - friction = pm_friction * 1.5f; // extra friction - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - //VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * newspeed; - } - - // accelerate - scale = PM_CmdScale( &pm->cmd ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - //for (i=0 ; i<3 ; i++) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - - wishvel = pml.forward * fmove + pml.right * smove; - //wishvel[2] += pm->cmd.upmove; - wishvel.z += pm->cmd.upmove; - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - - PM_Accelerate( wishdir, wishspeed, pm_accelerate ); - - // move - //VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin); - pm->ps.origin = pm->ps.origin + pm->ps.velocity * pml.frametime; -} - -static void PM_DropTimers( void ) -{ - // drop misc timing counter - if ( pm->ps.pm_time ) - { - if ( pml.msec >= pm->ps.pm_time ) - { - //pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps.pm_time = 0; - } - else - pm->ps.pm_time -= pml.msec; - } - - //bprintf("Time: %i\n", pm->ps.pm_time); - - // drop animation counter - /*if ( pm->ps->legsTimer > 0 ) - { - pm->ps->legsTimer -= pml.msec; - if ( pm->ps->legsTimer < 0 ) - pm->ps->legsTimer = 0; - } - - if ( pm->ps->torsoTimer > 0 ) - { - pm->ps->torsoTimer -= pml.msec; - if ( pm->ps->torsoTimer < 0 ) - pm->ps->torsoTimer = 0; - }*/ -} - -static void PM_FlyMove( void ) -{ - //int i; - Ogre::Vector3 wishvel; - float wishspeed; - Ogre::Vector3 wishdir; - float scale; - - // normal slowdown - PM_Friction (); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) - { - /*wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = 0;*/ - wishvel = Ogre::Vector3(0,0,0); - } - else - { - //for (i=0 ; i<3 ; i++) - //wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; - - //wishvel[2] += scale * pm->cmd.upmove; - wishvel.z += /*6.35f * */pm->cmd.upmove * scale; - } - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - - //wishspeed = VectorNormalize(wishdir); - wishspeed = VectorNormalize(wishdir); - - PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate); - - PM_StepSlideMove( false ); -} - - -void PM_SetWaterLevel( playerMove* const pm ) -{ - Ogre::Vector3 point; - //int cont; - int sample1; - int sample2; - - // - // get waterlevel, accounting for ducking - // - - pm->ps.waterlevel = WL_DRYLAND; - pm->ps.watertype = 0; - - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] + MINS_Z + 1; */ - point.x = pm->ps.origin.x; - point.y = pm->ps.origin.y; - point.z = pm->ps.origin.z + MINS_Z + 1; - - //cont = pm->pointcontents( point, pm->ps->clientNum ); - bool checkWater = (pml.hasWater && pml.waterHeight > point.z); - //if ( cont & MASK_WATER ) - if ( checkWater) - { - sample2 = /*pm->ps.viewheight*/DEFAULT_VIEWHEIGHT - MINS_Z; - sample1 = sample2 / 2; - - pm->ps.watertype = CONTENTS_WATER;//cont; - pm->ps.waterlevel = WL_ANKLE; - //point[2] = pm->ps->origin[2] + MINS_Z + sample1; - point.z = pm->ps.origin.z + MINS_Z + sample1; - checkWater = (pml.hasWater && pml.waterHeight > point.z); - //cont = pm->pointcontents (point, pm->ps->clientNum ); - //if ( cont & MASK_WATER ) - if (checkWater) - { - pm->ps.waterlevel = WL_WAIST; - //point[2] = pm->ps->origin[2] + MINS_Z + sample2; - point.z = pm->ps.origin.z + MINS_Z + sample2; - //cont = pm->pointcontents (point, pm->ps->clientNum ); - //if ( cont & MASK_WATER ) - checkWater = (pml.hasWater && pml.waterHeight > point.z); - if (checkWater ) - pm->ps.waterlevel = WL_UNDERWATER; - } - } -} - -void PmoveSingle (playerMove* const pmove) -{ - pmove->ps.counter--; - //pm = pmove; - - // Aedra doesn't support Q3-style VM traps D: //while(1); - - // this counter lets us debug movement problems with a journal - // by setting a conditional breakpoint fot the previous frame - //c_pmove++; - - // clear results - //pm->numtouch = 0; - pm->ps.watertype = 0; - pm->ps.waterlevel = WL_DRYLAND; - - //if ( pm->ps->stats[STAT_HEALTH] <= 0 ) - //pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies - - - // make sure walking button is clear if they are running, to avoid - // proxy no-footsteps cheats - //if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) - //pm->cmd.buttons &= ~BUTTON_WALKING; - - - // set the talk balloon flag - //if ( pm->cmd.buttons & BUTTON_TALK ) - //pm->ps->eFlags |= EF_TALK; - //else - //pm->ps->eFlags &= ~EF_TALK; - - // set the firing flag for continuous beam weapons - /*if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION - && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) - pm->ps->eFlags |= EF_FIRING; - else - pm->ps->eFlags &= ~EF_FIRING;*/ - - // clear the respawned flag if attack and use are cleared - /*if ( pm->ps->stats[STAT_HEALTH] > 0 && - !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) - pm->ps->pm_flags &= ~PMF_RESPAWNED;*/ - - // if talk button is down, dissallow all other input - // this is to prevent any possible intercept proxy from - // adding fake talk balloons - /*if ( pmove->cmd.buttons & BUTTON_TALK ) - { - // keep the talk button set tho for when the cmd.serverTime > 66 msec - // and the same cmd is used multiple times in Pmove - pmove->cmd.buttons = BUTTON_TALK; - pmove->cmd.forwardmove = 0; - pmove->cmd.rightmove = 0; - pmove->cmd.upmove = 0; - }*/ - - // clear all pmove local vars - memset (&pml, 0, sizeof(pml) ); - - // Aedra-specific code: - //pml.scene = global_lastscene; - - - // End Aedra-specific code - pml.hasWater = pmove->hasWater; - pml.isInterior = pmove->isInterior; - pml.waterHeight = pmove->waterHeight; - - // determine the time - pml.msec = pmove->cmd.serverTime - pm->ps.commandTime; - if ( pml.msec < 1 ) - pml.msec = 1; - else if ( pml.msec > 200 ) - pml.msec = 200; - - //pm->ps->commandTime = pmove->cmd.serverTime; - - // Commented out as a hack - pm->ps.commandTime = pmove->cmd.serverTime; - - // Handle state change procs: - if (pm->cmd.activating != pm->cmd.lastActivatingState) - { - if (!pm->cmd.lastActivatingState && pm->cmd.activating) - pm->cmd.procActivating = playerMove::playercmd::KEYDOWN; - else - pm->cmd.procActivating = playerMove::playercmd::KEYUP; - } - else - { - pm->cmd.procActivating = playerMove::playercmd::NO_CHANGE; - } - pm->cmd.lastActivatingState = pm->cmd.activating; - - if (pm->cmd.dropping != pm->cmd.lastDroppingState) - { - if (!pm->cmd.lastDroppingState && pm->cmd.dropping) - pm->cmd.procDropping = playerMove::playercmd::KEYDOWN; - else - pm->cmd.procDropping = playerMove::playercmd::KEYUP; - } - else - { - pm->cmd.procDropping = playerMove::playercmd::NO_CHANGE; - } - pm->cmd.lastDroppingState = pm->cmd.dropping; - - // save old org in case we get stuck - //VectorCopy (pm->ps->origin, pml.previous_origin); - pml.previous_origin = pm->ps.origin; - - // Copy over the lastframe origin - pmove->ps.lastframe_origin = pmove->ps.origin; - - //pmove->ps.lastframe_origin = pmove->ps.origin; - - // save old velocity for crashlanding - //VectorCopy (pm->ps->velocity, pml.previous_velocity); - pml.previous_velocity = pm->ps.velocity; - - pml.frametime = pml.msec * 0.001f; - - // update the viewangles - //PM_UpdateViewAngles( &(pm->ps), &(pm->cmd) ); - - AngleVectors (pm->ps.viewangles, &(pml.forward), &(pml.right), &(pml.up) ); - - //if ( pm->cmd.upmove < 10 ) - // not holding jump - //pm->ps->pm_flags &= ~PMF_JUMP_HELD; - - // decide if backpedaling animations should be used - /*if ( pm->cmd.forwardmove < 0 ) - pm->ps->pm_flags |= PMF_BACKWARDS_RUN; - else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) - pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;*/ - - /*if ( pm->ps->pm_type >= PM_DEAD ) - { - pm->cmd.forwardmove = 0; - pm->cmd.rightmove = 0; - pm->cmd.upmove = 0; - }*/ - - if ( pm->ps.move_type == PM_SPECTATOR ) - { - - //PM_CheckDuck (); - PM_FlyMove (); - PM_DropTimers (); - return; - } - - if ( pm->ps.move_type == PM_NOCLIP ) - { - - PM_NoclipMove (); - PM_DropTimers (); - return; - } - - if (pm->ps.move_type == PM_FREEZE){ - - return; // no movement at all - - } - - if ( pm->ps.move_type == PM_INTERMISSION || pm->ps.move_type == PM_SPINTERMISSION){ - return; // no movement at all - } - - // set watertype, and waterlevel - PM_SetWaterLevel(pmove); - pml.previous_waterlevel = pmove->ps.waterlevel; - - // set mins, maxs, and viewheight - //PM_CheckDuck (); - - // set groundentity - PM_GroundTrace(); - - /*if ( pm->ps->pm_type == PM_DEAD ) - PM_DeadMove (); - - PM_DropTimers();*/ - - PM_DropTimers(); - -/*#ifdef MISSIONPACK - if ( pm->ps->powerups[PW_INVULNERABILITY] ) { - PM_InvulnerabilityMove(); - } else -#endif*/ - /*if ( pm->ps->powerups[PW_FLIGHT] ) - // flight powerup doesn't allow jump and has different friction - PM_FlyMove(); - else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - { - PM_GrappleMove(); - // We can wiggle a bit - PM_AirMove(); - } - else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) - PM_WaterJumpMove();*/ - if ( pmove->ps.waterlevel > 1 ) - // swimming - PM_WaterMove(pmove); - else if ( pml.walking ) - { - - // walking on ground - PM_WalkMove(pmove); - //bprintf("WalkMove\n"); - } - else - { - // airborne - //std::cout << "AIRMOVE\n"; - PM_AirMove(); - //bprintf("AirMove\n"); - } - - //PM_Animate(); - - // set groundentity, watertype, and waterlevel - PM_GroundTrace(); - PM_SetWaterLevel(pmove); - - // weapons - /*PM_Weapon(); - - // torso animation - PM_TorsoAnimation(); - - // footstep events / legs animations - PM_Footsteps(); - - // entering / leaving water splashes - PM_WaterEvents(); - - // snap some parts of playerstate to save network bandwidth - trap_SnapVector( pm->ps->velocity );*/ -} - -void Ext_UpdateViewAngles(playerMove* const pm) -{ - playerMove::playerStruct* const ps = &(pm->ps); - playerMove::playercmd* const cmd = &(pm->cmd); - PM_UpdateViewAngles(ps, cmd); -} - -void Pmove (playerMove* const pmove) -{ - // warning: unused variable ‘fmove’ - //int fmove = pmove->cmd.forwardmove; - - pm = pmove; - - int finalTime; - - finalTime = pmove->cmd.serverTime; - - pmove->ps.commandTime = 40; - - if ( finalTime < pmove->ps.commandTime ) - return; // should not happen - - if ( finalTime > pmove->ps.commandTime + 1000 ) - pmove->ps.commandTime = finalTime - 1000; - - pmove->ps.pmove_framecount = (pmove->ps.pmove_framecount + 1) & ( (1 << PS_PMOVEFRAMECOUNTBITS) - 1); - - // chop the move up if it is too long, to prevent framerate - // dependent behavior - while ( pmove->ps.commandTime != finalTime ) - { - int msec; - - msec = finalTime - pmove->ps.commandTime; - - if ( pmove->pmove_fixed ) - { - if ( msec > pmove->pmove_msec ) - msec = pmove->pmove_msec; - } - else - { - if ( msec > 66 ) - msec = 66; - } - - pmove->cmd.serverTime = pmove->ps.commandTime + msec; - - if (pmove->isInterior) - { - PmoveSingle( pmove ); - } - else - { - PmoveSingle( pmove ); - /* - std::map::const_iterator it = ExtCellLookup.find(PositionToCell(pmove->ps.origin) ); - if (it != ExtCellLookup.end() ) - { - pmove->traceObj->incellptr = it->second; - }*/ - } - - //if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) - //pmove->cmd.upmove = 20; - } - - //pmove->ps.last_compute_time = GetTimeQPC(); - //pmove->ps.lerp_multiplier = (pmove->ps.origin - pmove->ps.lastframe_origin);// * (1.000 / 31.0); - - //PM_CheckStuck(); - -} - - diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h deleted file mode 100644 index 29a0504712..0000000000 --- a/libs/openengine/bullet/pmove.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef OENGINE_BULLET_PMOVE_H -#define OENGINE_BULLET_PMOVE_H -/* -This source file is a *modified* version of various header files from the Quake 3 Arena source code, -which was released under the GNU GPL (v2) in 2005. -Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. -*/ - -#include -#include - -#include - -//#include "GameMath.h" -//#include "GameTime.h" - -// Forwards-declare it! - -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - -/*#ifndef COMPILING_PMOVE -#include "Scene.h" -extern SceneInstance* global_lastscene; -#endif*/ - -static const Ogre::Vector3 halfExtentsDefault(14.64f * 2, 14.24f * 2, 33.25f * 2); - -#define MAX_CLIP_PLANES 5 -#define OVERCLIP 1.001f -//#define STEPSIZE 18 // 18 is way too much -#define STEPSIZE (9) -#ifndef M_PI - #define M_PI 3.14159265358979323846f -#endif -#define YAW 0 -#define PITCH /*1*/2 -#define ROLL /*2*/1 -#define SHORT2ANGLE(x) ( (x) * (360.0f / 65536.0f) ) -#define ANGLE2SHORT(x) ( (const short)( (x) / (360.0f / 65536.0f) ) ) -#define GENTITYNUM_BITS 10 // don't need to send any more -#define MAX_GENTITIES (1 << GENTITYNUM_BITS) -#define ENTITYNUM_NONE (MAX_GENTITIES - 1) -#define ENTITYNUM_WORLD (MAX_GENTITIES - 2) -#define MIN_WALK_NORMAL .7f // can't walk on very steep slopes -#define PS_PMOVEFRAMECOUNTBITS 6 -#define MINS_Z -24 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 -#define DEAD_VIEWHEIGHT (-16) -#define CONTENTS_SOLID 1 // an eye is never valid in a solid -#define CONTENTS_LAVA 8 -#define CONTENTS_SLIME 16 -#define CONTENTS_WATER 32 -#define CONTENTS_FOG 64 -static const float pm_accelerate = 10.0f; -static const float pm_stopspeed = 100.0f; -static const float pm_friction = 12.0f; -static const float pm_flightfriction = 3.0f; -static const float pm_waterfriction = 1.0f; -static const float pm_airaccelerate = 1.0f; -static const float pm_swimScale = 0.50f; -static const float pm_duckScale = 0.25f; -static const float pm_flyaccelerate = 8.0f; -static const float pm_wateraccelerate = 4.0f; - -enum pmtype_t -{ - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar -}; - -enum waterlevel_t -{ - WL_DRYLAND = 0, - WL_ANKLE, - WL_WAIST, - WL_UNDERWATER -}; - - -//#include "bprintf.h" - -struct playerMove -{ - struct playerStruct - { - playerStruct() : gravity(800.0f), speed(480.0f), jump_velocity(270), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0), snappingImplemented(true), bSnap(false), counter(-1), halfExtents(halfExtentsDefault) - { - origin = Ogre::Vector3(0.0f, 0.0f, 0.0f); - velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - viewangles = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - delta_angles[0] = delta_angles[1] = delta_angles[2] = 0; - - lastframe_origin.x = lastframe_origin.y = lastframe_origin.z = 0; - lerp_multiplier.x = lerp_multiplier.y = lerp_multiplier.z = 0; - } - - inline void SpeedUp(void) - { - //printf("speed up to: %f\n", speed); - speed *= 1.25f; - } - - inline void SpeedDown(void) - { - //printf("speed down to %f\n", speed); - speed /= 1.25f; - } - - Ogre::Vector3 velocity; - Ogre::Vector3 origin; - Ogre::Vector3 halfExtents; - bool bSnap; - bool snappingImplemented; - int counter; - float gravity; // default = 800 - float speed; // default = 320 - float jump_velocity; //default = 270 - - int commandTime; // the time at which this command was issued (in milliseconds) - - int pm_time; - - Ogre::Vector3 viewangles; - - int groundEntityNum; - - int pmove_framecount; - - int watertype; - waterlevel_t waterlevel; - - signed short delta_angles[3]; - - pmtype_t move_type; - - float last_compute_time; - Ogre::Vector3 lastframe_origin; - Ogre::Vector3 lerp_multiplier; - } ps; - - struct playercmd - { - enum CMDstateChange - { - NO_CHANGE, - KEYDOWN, - KEYUP - }; - - playercmd() : forwardmove(0), rightmove(0), upmove(0), serverTime(50), ducking(false), - activating(false), lastActivatingState(false), procActivating(NO_CHANGE), - dropping(false), lastDroppingState(false), procDropping(NO_CHANGE) - { - angles[0] = angles[1] = angles[2] = 0; - } - - int serverTime; - - short angles[3]; - - signed char forwardmove; - signed char rightmove; - signed char upmove; - - bool ducking; - bool activating; // if the user is holding down the activate button - bool dropping; // if the user is dropping an item - - bool lastActivatingState; - bool lastDroppingState; - - CMDstateChange procActivating; - CMDstateChange procDropping; - } cmd; - - playerMove() : msec(50), pmove_fixed(false), pmove_msec(50), waterHeight(0), isInterior(true), hasWater(false) - { - } - - int msec; - int pmove_msec; - bool pmove_fixed; - int waterHeight; - bool hasWater; - bool isInterior; - OEngine::Physic::PhysicEngine* mEngine; -}; - -void Pmove (playerMove* const pmove); -void Ext_UpdateViewAngles(playerMove* const pm); -void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) ; -#endif diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 138411e11b..618f6ee652 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -7,7 +7,6 @@ #include #include "physic.hpp" -#include "pmove.h" enum traceWorldType @@ -105,7 +104,6 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr { results->endpos = end; results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - results->entityNum = ENTITYNUM_NONE; results->fraction = 1.0f; } else @@ -113,6 +111,5 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr results->fraction = out.fraction; results->planenormal = out.hitNormal; results->endpos = (end-start)*results->fraction + start; - results->entityNum = ENTITYNUM_WORLD; } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 94708d403f..7b17da178e 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -20,10 +20,6 @@ struct traceResults float fraction; - int surfaceFlags; - int contents; - int entityNum; - bool allsolid; bool startsolid; }; From 35b68a3c400ed79762338835ef77b48b5bde95b0 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 19 Feb 2013 15:58:01 +0100 Subject: [PATCH 0388/1483] Fixed accidental profile deletion and added sorting by date --- apps/launcher/CMakeLists.txt | 6 ++ apps/launcher/datafilespage.cpp | 71 +++++++++++-------- apps/launcher/datafilespage.hpp | 4 +- apps/launcher/maindialog.cpp | 2 - apps/launcher/model/pluginsproxymodel.cpp | 17 +++++ apps/launcher/model/pluginsproxymodel.hpp | 18 +++++ apps/launcher/settings/gamesettings.cpp | 55 ++++++++------ apps/launcher/settings/launchersettings.cpp | 17 ++--- apps/launcher/settings/settingsbase.hpp | 2 - .../fileorderlist/model/datafilesmodel.cpp | 21 +++++- 10 files changed, 146 insertions(+), 67 deletions(-) create mode 100644 apps/launcher/model/pluginsproxymodel.cpp create mode 100644 apps/launcher/model/pluginsproxymodel.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 2c17e06b40..59cccad5fa 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -5,6 +5,8 @@ set(LAUNCHER maindialog.cpp playpage.cpp + model/pluginsproxymodel.cpp + settings/gamesettings.cpp settings/graphicssettings.cpp settings/launchersettings.cpp @@ -22,6 +24,8 @@ set(LAUNCHER_HEADER maindialog.hpp playpage.hpp + model/pluginsproxymodel.hpp + settings/gamesettings.hpp settings/graphicssettings.hpp settings/launchersettings.hpp @@ -39,6 +43,8 @@ set(LAUNCHER_HEADER_MOC maindialog.hpp playpage.hpp + model/pluginsproxymodel.hpp + utils/comboboxlineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index e0ebefa589..4ecb67e4e8 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -9,6 +9,8 @@ #include #include +#include "model/pluginsproxymodel.hpp" + #include "settings/gamesettings.hpp" #include "settings/launchersettings.hpp" @@ -63,7 +65,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); mMastersProxyModel->setSourceModel(mDataFilesModel); - mPluginsProxyModel = new QSortFilterProxyModel(); + mPluginsProxyModel = new PluginsProxyModel(); mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); mPluginsProxyModel->setSourceModel(mDataFilesModel); @@ -97,6 +99,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersTable = new QTableView(this); mMastersTable->setModel(mMastersProxyModel); mMastersTable->setObjectName("MastersTable"); + mMastersTable->setSortingEnabled(false); mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection); mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -108,19 +111,12 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersTable->verticalHeader()->setDefaultSectionSize(height); mMastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); mMastersTable->verticalHeader()->hide(); - mMastersTable->setColumnHidden(1, true); - mMastersTable->setColumnHidden(2, true); - mMastersTable->setColumnHidden(3, true); - mMastersTable->setColumnHidden(4, true); - mMastersTable->setColumnHidden(5, true); - mMastersTable->setColumnHidden(6, true); - mMastersTable->setColumnHidden(7, true); - mMastersTable->setColumnHidden(8, true); mPluginsTable = new QTableView(this); mPluginsTable->setModel(mFilterProxyModel); mPluginsTable->setObjectName("PluginsTable"); mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); + mPluginsTable->setSortingEnabled(false); mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); mPluginsTable->setSelectionMode(QAbstractItemView::SingleSelection); mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -131,14 +127,6 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mPluginsTable->verticalHeader()->setDefaultSectionSize(height); mPluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mPluginsTable->setColumnHidden(1, true); - mPluginsTable->setColumnHidden(2, true); - mPluginsTable->setColumnHidden(3, true); - mPluginsTable->setColumnHidden(4, true); - mPluginsTable->setColumnHidden(5, true); - mPluginsTable->setColumnHidden(6, true); - mPluginsTable->setColumnHidden(7, true); - mPluginsTable->setColumnHidden(8, true); // Add both tables to a splitter mSplitter = new QSplitter(this); @@ -185,12 +173,11 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + + connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); - connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); - connect(mSplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); createActions(); @@ -250,9 +237,13 @@ void DataFilesPage::setupDataFiles() mDataFilesModel->addFiles(dataLocal); } + // Sort by date accessed for now + mDataFilesModel->sort(3); + QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + mProfilesComboBox->setCurrentIndex(-1); mProfilesComboBox->addItems(profiles); // Add the current profile if empty @@ -262,12 +253,18 @@ void DataFilesPage::setupDataFiles() if (mProfilesComboBox->findText(QString("Default")) == -1) mProfilesComboBox->addItem(QString("Default")); - if (profile.isEmpty()) { + + if (profile.isEmpty() || profile == QLatin1String("Default")) { mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(QString("Default"))); } else { + mProfilesComboBox->setEditEnabled(true); mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); } + // We do this here to prevent deletion of profiles when initializing the combobox + connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); + connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); + loadSettings(); } @@ -301,10 +298,8 @@ void DataFilesPage::saveSettings() { QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); - if (profile.isEmpty()) { - profile = mProfilesComboBox->currentText(); - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), profile); - } + if (profile.isEmpty()) + return; mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); @@ -360,6 +355,28 @@ void DataFilesPage::updateSplitter() mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1))); } +void DataFilesPage::updateViews() +{ + // Ensure the columns are hidden because sort() re-enables them + mMastersTable->setColumnHidden(1, true); + mMastersTable->setColumnHidden(2, true); + mMastersTable->setColumnHidden(3, true); + mMastersTable->setColumnHidden(4, true); + mMastersTable->setColumnHidden(5, true); + mMastersTable->setColumnHidden(6, true); + mMastersTable->setColumnHidden(7, true); + mMastersTable->setColumnHidden(8, true); + + mPluginsTable->setColumnHidden(1, true); + mPluginsTable->setColumnHidden(2, true); + mPluginsTable->setColumnHidden(3, true); + mPluginsTable->setColumnHidden(4, true); + mPluginsTable->setColumnHidden(5, true); + mPluginsTable->setColumnHidden(6, true); + mPluginsTable->setColumnHidden(7, true); + mPluginsTable->setColumnHidden(8, true); +} + void DataFilesPage::deleteProfile() { QString profile = mProfilesComboBox->currentText(); @@ -441,7 +458,7 @@ void DataFilesPage::uncheck() void DataFilesPage::refresh() { - mDataFilesModel->sort(0); +// mDataFilesModel->sort(0); // Refresh the plugins table mPluginsTable->scrollToTop(); @@ -512,7 +529,6 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre saveSettings(); mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); - mDataFilesModel->uncheckAll(); loadSettings(); } @@ -532,7 +548,6 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre // Remove the profile from the combobox mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - mDataFilesModel->uncheckAll(); loadSettings(); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index e6b4194bdc..2561aa3d17 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -18,6 +18,7 @@ class TextInputDialog; class ProfilesComboBox; class GameSettings; class LauncherSettings; +class PluginsProxyModel; namespace Files { struct ConfigurationManager; } @@ -43,6 +44,7 @@ public slots: void profileRenamed(const QString &previous, const QString ¤t); void updateOkButton(const QString &text); void updateSplitter(); + void updateViews(); // Action slots void newProfile(); @@ -58,7 +60,7 @@ public slots: private: DataFilesModel *mDataFilesModel; - QSortFilterProxyModel *mPluginsProxyModel; + PluginsProxyModel *mPluginsProxyModel; QSortFilterProxyModel *mMastersProxyModel; QSortFilterProxyModel *mFilterProxyModel; diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 7b453671c7..15f2690dad 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -206,8 +206,6 @@ void MainDialog::saveSettings() mLauncherSettings.setValue(QString("General/MainWindow/posx"), posX); mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY); - - qDebug() << "size: " << width << height; } void MainDialog::writeSettings() diff --git a/apps/launcher/model/pluginsproxymodel.cpp b/apps/launcher/model/pluginsproxymodel.cpp new file mode 100644 index 0000000000..6be152b555 --- /dev/null +++ b/apps/launcher/model/pluginsproxymodel.cpp @@ -0,0 +1,17 @@ +#include "pluginsproxymodel.hpp" + +PluginsProxyModel::PluginsProxyModel(QObject *parent) : + QSortFilterProxyModel(parent) +{ +} + +PluginsProxyModel::~PluginsProxyModel() +{ +} + +QVariant PluginsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation != Qt::Vertical || role != Qt::DisplayRole) + return QSortFilterProxyModel::headerData(section, orientation, role); + return section + 1; +} diff --git a/apps/launcher/model/pluginsproxymodel.hpp b/apps/launcher/model/pluginsproxymodel.hpp new file mode 100644 index 0000000000..8fde732361 --- /dev/null +++ b/apps/launcher/model/pluginsproxymodel.hpp @@ -0,0 +1,18 @@ +#ifndef PLUGINSPROXYMODEL_HPP +#define PLUGINSPROXYMODEL_HPP + +#include + +class QVariant; + +class PluginsProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + explicit PluginsProxyModel(QObject *parent = 0); + ~PluginsProxyModel(); + + QVariant headerData(int section, Qt::Orientation orientation, int role) const; +}; + +#endif // PLUGINSPROXYMODEL_HPP diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index f87937228a..fcf6f8b8a7 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -21,8 +21,6 @@ GameSettings::~GameSettings() void GameSettings::validatePaths() { - qDebug() << "validate paths!"; - if (mSettings.isEmpty()) return; @@ -35,9 +33,6 @@ void GameSettings::validatePaths() // Parse the data dirs to convert the tokenized paths mCfgMgr.processPaths(dataDirs); - -// // Replace the existing data paths with valid untokenized ones -// mSettings.remove(QString("data")); mDataDirs.clear(); for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { @@ -59,7 +54,6 @@ void GameSettings::validatePaths() dataDirs.push_back(Files::PathContainer::value_type(local.toStdString())); mCfgMgr.processPaths(dataDirs); -// mSettings.remove(QString("data-local")); if (!dataDirs.empty()) { QString path = QString::fromStdString(dataDirs.front().string()); @@ -92,23 +86,21 @@ bool GameSettings::readFile(QTextStream &stream) if (line.isEmpty() || line.startsWith("#")) continue; - qDebug() << "line: " << line; if (keyRe.indexIn(line) != -1) { QString key = keyRe.cap(1).simplified(); QString value = keyRe.cap(2).simplified(); - qDebug() << "key: " << key; - // There can be multiple data keys - if (key == QLatin1String("data")) { + // There can be multiple keys + if (key == QLatin1String("data") || + key == QLatin1String("master") || + key == QLatin1String("plugin")) + { // Remove keys from previous config and overwrite them mSettings.remove(key); QStringList values = cache.values(key); - if (!values.contains(value)) { - // Do not insert duplicate values - qDebug() << "values does not contain: " << value << values; + if (!values.contains(value)) // Do not insert duplicate values cache.insertMulti(key, value); - } } else { cache.insert(key, value); } @@ -137,23 +129,42 @@ bool GameSettings::readFile(QTextStream &stream) // Merge the changed keys with those which didn't mSettings.unite(cache); validatePaths(); - qDebug() << mSettings; + return true; } bool GameSettings::writeFile(QTextStream &stream) { + // Iterate in reverse order to preserve insertion order QMapIterator i(mSettings); - while (i.hasNext()) { - i.next(); + i.toBack(); - // Quote values with spaces - if (i.value().contains(" ")) { - stream << i.key() << "=\"" << i.value() << "\"\n"; - } else { - stream << i.key() << "=" << i.value() << "\n"; + while (i.hasPrevious()) { + i.previous(); + + if (i.key() == QLatin1String("master") || i.key() == QLatin1String("plugin")) + continue; + + // Quote paths with spaces + if (i.key() == QLatin1String("data") || i.key() == QLatin1String("data")) { + if (i.value().contains(" ")) { + stream << i.key() << "=\"" << i.value() << "\"\n"; + continue; + } } + stream << i.key() << "=" << i.value() << "\n"; + + } + + QStringList masters = mSettings.values(QString("master")); + for (int i = masters.count(); i--;) { + stream << "master=" << masters.at(i) << "\n"; + } + + QStringList plugins = mSettings.values(QString("plugin")); + for (int i = plugins.count(); i--;) { + stream << "plugin=" << plugins.at(i) << "\n"; } return true; diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index 07502ea027..e9730c2357 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -26,7 +26,6 @@ QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags) QStringList keys = settings.keys(); foreach (const QString ¤tKey, keys) { - qDebug() << "key is: " << currentKey << "value: " << settings.value(currentKey); if (currentKey.startsWith(key)) result.append(settings.value(currentKey)); } @@ -38,16 +37,15 @@ QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags) QStringList LauncherSettings::subKeys(const QString &key) { QMap settings = SettingsBase::getSettings(); - QStringList keys = settings.keys(); + QStringList keys = settings.uniqueKeys(); QRegExp keyRe("(.+)/"); QStringList result; foreach (const QString ¤tKey, keys) { - qDebug() << "key is: " << currentKey; + if (keyRe.indexIn(currentKey) != -1) { - qDebug() << "text: " << keyRe.cap(1) << keyRe.cap(2); QString prefixedKey = keyRe.cap(1); if(prefixedKey.startsWith(key)) { @@ -55,16 +53,11 @@ QStringList LauncherSettings::subKeys(const QString &key) QString subKey = prefixedKey.remove(key); if (!subKey.isEmpty()) result.append(subKey); - //qDebug() << keyRe.cap(2).simplified(); } - } else { - qDebug() << "no match"; } } result.removeDuplicates(); - qDebug() << result; - return result; } @@ -75,8 +68,10 @@ bool LauncherSettings::writeFile(QTextStream &stream) QMap settings = SettingsBase::getSettings(); QMapIterator i(settings); - while (i.hasNext()) { - i.next(); + i.toBack(); + + while (i.hasPrevious()) { + i.previous(); QString prefix; QString key; diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index e70bc0d721..321426eed8 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -75,7 +75,6 @@ public: QStringList values = mCache.values(key); if (!values.contains(value)) { - // QMap will replace the value if key exists, QMultiMap creates a new one mCache.insertMulti(key, value); } } @@ -96,7 +95,6 @@ public: // Merge the changed keys with those which didn't mSettings.unite(mCache); - qDebug() << mSettings; return true; } diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 036394800a..4e9b69dc27 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -229,10 +229,29 @@ bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2) return e1->fileName().toLower() < e2->fileName().toLower(); } +bool lessThanDate(const EsmFile *e1, const EsmFile *e2) +{ + if (e1->modified().toString(Qt::ISODate) < e2->modified().toString(Qt::ISODate)) { + return true; + } else { + return false; + } +// if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) +// return false; + +// return e1->fileName().toLower() < e2->fileName().toLower(); +} + void DataFilesModel::sort(int column, Qt::SortOrder order) { emit layoutAboutToBeChanged(); - qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile); + + if (column == 3) { + qSort(mFiles.begin(), mFiles.end(), lessThanDate); + } else { + qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile); + } + emit layoutChanged(); } From 66743ecee70623d2d97291af7268fdcbf3a614e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 07:00:22 -0800 Subject: [PATCH 0389/1483] Remove some unused trace fields --- libs/openengine/bullet/trace.cpp | 39 +++++--------------------------- libs/openengine/bullet/trace.h | 3 --- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 618f6ee652..2f52d669a4 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -29,14 +29,12 @@ struct NewPhysTraceResults Ogre::Vector3 endPos; Ogre::Vector3 hitNormal; float fraction; - bool startSolid; //const Object* hitObj; }; -template -static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, - OEngine::Physic::PhysicEngine* enginePass) +static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, + const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, + OEngine::Physic::PhysicEngine* enginePass) { const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); @@ -49,7 +47,7 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); - newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; + newTraceCallback.m_collisionFilterMask = Only_Collision; enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); @@ -66,24 +64,6 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve out->endPos.y = tracehitpos.y(); out->endPos.z = tracehitpos.z(); - // StartSolid test: - { - out->startSolid = false; - if(isInterior) - { - // If inside and out of the tree, we're solid - btVector3 aabbMin, aabbMax; - enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); - btVector3 point(start.x, start.y, start.z); - if(!TestPointAgainstAabb2(aabbMin, aabbMax, point)) - { - //We're solid - //THIS NEEDS TO BE TURNED OFF IF WE WANT FALLING IN EXTERIORS TO WORK CORRECTLY!!!!!!! - //out->startSolid = true; - } - } - } - return newTraceCallback.hasHit(); } @@ -91,15 +71,8 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object { NewPhysTraceResults out; - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, - Ogre::Vector3(0.0f, 0.0f, 0.0f), - isInterior, enginePass); - if (out.fraction < 0.001f) - results->startsolid = true; - else - results->startsolid = false; - results->allsolid = out.startSolid; - + bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), + isInterior, enginePass); if(!hasHit) { results->endpos = end; diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 7b17da178e..34ecb7454c 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -19,9 +19,6 @@ struct traceResults Ogre::Vector3 planenormal; float fraction; - - bool allsolid; - bool startsolid; }; void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); From 2172fb42298a4faddc7a0ae2a37a04aa3a4e15b1 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 19 Feb 2013 16:41:33 +0100 Subject: [PATCH 0390/1483] Added checkable message box class --- apps/launcher/CMakeLists.txt | 5 +- apps/launcher/utils/checkablemessagebox.cpp | 243 ++++++++++++++++++++ apps/launcher/utils/checkablemessagebox.hpp | 71 ++++++ 3 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 apps/launcher/utils/checkablemessagebox.cpp create mode 100644 apps/launcher/utils/checkablemessagebox.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 59cccad5fa..b2e6c70098 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -11,6 +11,7 @@ set(LAUNCHER settings/graphicssettings.cpp settings/launchersettings.cpp + utils/checkablemessagebox.cpp utils/comboboxlineedit.cpp utils/profilescombobox.cpp utils/textinputdialog.cpp @@ -31,7 +32,8 @@ set(LAUNCHER_HEADER settings/launchersettings.hpp settings/settingsbase.hpp - utils/comboboxlineedit.cpp + utils/checkablemessagebox.hpp + utils/comboboxlineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp ) @@ -45,6 +47,7 @@ set(LAUNCHER_HEADER_MOC model/pluginsproxymodel.hpp + utils/checkablemessagebox.hpp utils/comboboxlineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp diff --git a/apps/launcher/utils/checkablemessagebox.cpp b/apps/launcher/utils/checkablemessagebox.cpp new file mode 100644 index 0000000000..8aa01d1018 --- /dev/null +++ b/apps/launcher/utils/checkablemessagebox.cpp @@ -0,0 +1,243 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "checkablemessagebox.hpp" + + +/* + class CheckableMessageBox + Modified from the one used in Qt Creator + + A messagebox suitable for questions with a + "Do not ask me again" checkbox. + + Emulates the QMessageBox API with + static conveniences. The message label can open external URLs. +*/ + + +class CheckableMessageBoxPrivate +{ +public: + CheckableMessageBoxPrivate(QDialog *q) + : clickedButton(0) + { + QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + + pixmapLabel = new QLabel(q); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth()); + pixmapLabel->setSizePolicy(sizePolicy); + pixmapLabel->setVisible(false); + + QSpacerItem *pixmapSpacer = + new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); + + messageLabel = new QLabel(q); + messageLabel->setMinimumSize(QSize(300, 0)); + messageLabel->setWordWrap(true); + messageLabel->setOpenExternalLinks(true); + messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse); + + QSpacerItem *checkBoxRightSpacer = + new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum); + QSpacerItem *buttonSpacer = + new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum); + + checkBox = new QCheckBox(q); + checkBox->setText(CheckableMessageBox::tr("Do not ask again")); + + buttonBox = new QDialogButtonBox(q); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + + QVBoxLayout *verticalLayout = new QVBoxLayout(); + verticalLayout->addWidget(pixmapLabel); + verticalLayout->addItem(pixmapSpacer); + + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->addLayout(verticalLayout); + horizontalLayout_2->addWidget(messageLabel); + + QHBoxLayout *horizontalLayout = new QHBoxLayout(); + horizontalLayout->addWidget(checkBox); + horizontalLayout->addItem(checkBoxRightSpacer); + + QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q); + verticalLayout_2->addLayout(horizontalLayout_2); + verticalLayout_2->addLayout(horizontalLayout); + verticalLayout_2->addItem(buttonSpacer); + verticalLayout_2->addWidget(buttonBox); + } + + QLabel *pixmapLabel; + QLabel *messageLabel; + QCheckBox *checkBox; + QDialogButtonBox *buttonBox; + QAbstractButton *clickedButton; +}; + +CheckableMessageBox::CheckableMessageBox(QWidget *parent) : + QDialog(parent), + d(new CheckableMessageBoxPrivate(this)) +{ + setModal(true); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept())); + connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject())); + connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)), + SLOT(slotClicked(QAbstractButton*))); +} + +CheckableMessageBox::~CheckableMessageBox() +{ + delete d; +} + +void CheckableMessageBox::slotClicked(QAbstractButton *b) +{ + d->clickedButton = b; +} + +QAbstractButton *CheckableMessageBox::clickedButton() const +{ + return d->clickedButton; +} + +QDialogButtonBox::StandardButton CheckableMessageBox::clickedStandardButton() const +{ + if (d->clickedButton) + return d->buttonBox->standardButton(d->clickedButton); + return QDialogButtonBox::NoButton; +} + +QString CheckableMessageBox::text() const +{ + return d->messageLabel->text(); +} + +void CheckableMessageBox::setText(const QString &t) +{ + d->messageLabel->setText(t); +} + +QPixmap CheckableMessageBox::iconPixmap() const +{ + if (const QPixmap *p = d->pixmapLabel->pixmap()) + return QPixmap(*p); + return QPixmap(); +} + +void CheckableMessageBox::setIconPixmap(const QPixmap &p) +{ + d->pixmapLabel->setPixmap(p); + d->pixmapLabel->setVisible(!p.isNull()); +} + +bool CheckableMessageBox::isChecked() const +{ + return d->checkBox->isChecked(); +} + +void CheckableMessageBox::setChecked(bool s) +{ + d->checkBox->setChecked(s); +} + +QString CheckableMessageBox::checkBoxText() const +{ + return d->checkBox->text(); +} + +void CheckableMessageBox::setCheckBoxText(const QString &t) +{ + d->checkBox->setText(t); +} + +bool CheckableMessageBox::isCheckBoxVisible() const +{ + return d->checkBox->isVisible(); +} + +void CheckableMessageBox::setCheckBoxVisible(bool v) +{ + d->checkBox->setVisible(v); +} + +QDialogButtonBox::StandardButtons CheckableMessageBox::standardButtons() const +{ + return d->buttonBox->standardButtons(); +} + +void CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s) +{ + d->buttonBox->setStandardButtons(s); +} + +QPushButton *CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const +{ + return d->buttonBox->button(b); +} + +QPushButton *CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role) +{ + return d->buttonBox->addButton(text, role); +} + +QDialogButtonBox::StandardButton CheckableMessageBox::defaultButton() const +{ + foreach (QAbstractButton *b, d->buttonBox->buttons()) + if (QPushButton *pb = qobject_cast(b)) + if (pb->isDefault()) + return d->buttonBox->standardButton(pb); + return QDialogButtonBox::NoButton; +} + +void CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s) +{ + if (QPushButton *b = d->buttonBox->button(s)) { + b->setDefault(true); + b->setFocus(); + } +} + +QDialogButtonBox::StandardButton +CheckableMessageBox::question(QWidget *parent, + const QString &title, + const QString &question, + const QString &checkBoxText, + bool *checkBoxSetting, + QDialogButtonBox::StandardButtons buttons, + QDialogButtonBox::StandardButton defaultButton) +{ + CheckableMessageBox mb(parent); + mb.setWindowTitle(title); + mb.setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question)); + mb.setText(question); + mb.setCheckBoxText(checkBoxText); + mb.setChecked(*checkBoxSetting); + mb.setStandardButtons(buttons); + mb.setDefaultButton(defaultButton); + mb.exec(); + *checkBoxSetting = mb.isChecked(); + return mb.clickedStandardButton(); +} + +QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db) +{ + return static_cast(int(db)); +} diff --git a/apps/launcher/utils/checkablemessagebox.hpp b/apps/launcher/utils/checkablemessagebox.hpp new file mode 100644 index 0000000000..ceb437d4d9 --- /dev/null +++ b/apps/launcher/utils/checkablemessagebox.hpp @@ -0,0 +1,71 @@ +#ifndef CHECKABLEMESSAGEBOX_HPP +#define CHECKABLEMESSAGEBOX_HPP + +#include +#include +#include + +class CheckableMessageBoxPrivate; + +class CheckableMessageBox : public QDialog +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap) + Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked) + Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText) + Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons) + Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton) + +public: + explicit CheckableMessageBox(QWidget *parent); + virtual ~CheckableMessageBox(); + + static QDialogButtonBox::StandardButton + question(QWidget *parent, + const QString &title, + const QString &question, + const QString &checkBoxText, + bool *checkBoxSetting, + QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No, + QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No); + + QString text() const; + void setText(const QString &); + + bool isChecked() const; + void setChecked(bool s); + + QString checkBoxText() const; + void setCheckBoxText(const QString &); + + bool isCheckBoxVisible() const; + void setCheckBoxVisible(bool); + + QDialogButtonBox::StandardButtons standardButtons() const; + void setStandardButtons(QDialogButtonBox::StandardButtons s); + QPushButton *button(QDialogButtonBox::StandardButton b) const; + QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role); + + QDialogButtonBox::StandardButton defaultButton() const; + void setDefaultButton(QDialogButtonBox::StandardButton s); + + // See static QMessageBox::standardPixmap() + QPixmap iconPixmap() const; + void setIconPixmap (const QPixmap &p); + + // Query the result + QAbstractButton *clickedButton() const; + QDialogButtonBox::StandardButton clickedStandardButton() const; + + // Conversion convenience + static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton); + +private slots: + void slotClicked(QAbstractButton *b); + +private: + CheckableMessageBoxPrivate *d; +}; + +#endif // CHECKABLEMESSAGEBOX_HPP From 43d63929217c43092a56f7a07d1c78c6f15728d2 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 16 Feb 2013 20:56:17 +0100 Subject: [PATCH 0391/1483] Change the way pinnable window are made visible This ensure pinned window are not displayed in main menu, dialogue and container mode. --- apps/openmw/mwgui/window_pinnable_base.cpp | 10 ---------- apps/openmw/mwgui/window_pinnable_base.hpp | 1 - apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++++++++++++++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index 4ddf49d27b..2e66a4805c 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -11,16 +11,6 @@ WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::Win t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed); } -void WindowPinnableBase::setVisible(bool b) -{ - // Pinned windows can not be hidden - if (mPinned && !b) - return; - - WindowBase::setVisible(b); - mVisible = b; -} - void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName) { if ("PinToggle" == eventName) diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index 250dde1f85..c577564c79 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -11,7 +11,6 @@ namespace MWGui { public: WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - void setVisible(bool b); bool pinned() { return mPinned; } private: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e03b91216d..39f7d07767 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -310,9 +310,16 @@ void WindowManager::updateVisible() setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); - // If in game mode, don't show anything. + // If in game mode, show only the pinned windows if (gameMode) + { + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + return; + } GuiMode mode = mGuiModes.back(); @@ -327,6 +334,12 @@ void WindowManager::updateVisible() mSettingsWindow->setVisible(true); break; case GM_Console: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + mConsole->enable(); break; case GM_Scroll: From 3ba3c71556d4e9b8abeb0fab8c329c86bec81082 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Feb 2013 02:56:07 +0100 Subject: [PATCH 0392/1483] Make the "lock window" button to change state visually --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/exposedwindow.cpp | 26 ++++++++++++++++++++++ apps/openmw/mwgui/exposedwindow.hpp | 26 ++++++++++++++++++++++ apps/openmw/mwgui/window_pinnable_base.cpp | 11 +++++++++ apps/openmw/mwgui/window_pinnable_base.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ files/mygui/openmw_inventory_window.layout | 2 +- files/mygui/openmw_map_window.layout | 2 +- files/mygui/openmw_spell_window.layout | 2 +- files/mygui/openmw_stats_window.layout | 2 +- files/mygui/openmw_windows.skin.xml | 14 +++++++++++- 11 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 apps/openmw/mwgui/exposedwindow.cpp create mode 100644 apps/openmw/mwgui/exposedwindow.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index df679d4cbc..3dd5ed45d5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -30,7 +30,7 @@ add_openmw_dir (mwgui formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog trainingwindow travelwindow imagebutton + enchantingdialog trainingwindow travelwindow imagebutton exposedwindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/exposedwindow.cpp b/apps/openmw/mwgui/exposedwindow.cpp new file mode 100644 index 0000000000..fa37568d7b --- /dev/null +++ b/apps/openmw/mwgui/exposedwindow.cpp @@ -0,0 +1,26 @@ +#include "exposedwindow.hpp" + +#include "MyGUI_Window.h" + +namespace MWGui +{ + MyGUI::VectorWidgetPtr ExposedWindow::getSkinWidgetsByName (const std::string &name) + { + return MyGUI::Widget::getSkinWidgetsByName (name); + } + + MyGUI::Widget* ExposedWindow::getSkinWidget(const std::string & _name, bool _throw) + { + MyGUI::VectorWidgetPtr widgets = getSkinWidgetsByName (_name); + + if (widgets.empty()) + { + MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' not found in skin of layout '" << getName() << "'"); + return nullptr; + } + else + { + return widgets[0]; + } + } +} diff --git a/apps/openmw/mwgui/exposedwindow.hpp b/apps/openmw/mwgui/exposedwindow.hpp new file mode 100644 index 0000000000..906d0b4065 --- /dev/null +++ b/apps/openmw/mwgui/exposedwindow.hpp @@ -0,0 +1,26 @@ +#ifndef MWGUI_EXPOSEDWINDOW_H +#define MWGUI_EXPOSEDWINDOW_H + +#include "MyGUI_Window.h" + +namespace MWGui +{ + + /** + * @brief subclass to provide access to some Widget internals. + */ + class ExposedWindow : public MyGUI::Window + { + MYGUI_RTTI_DERIVED(ExposedWindow) + + public: + MyGUI::VectorWidgetPtr getSkinWidgetsByName (const std::string &name); + + MyGUI::Widget* getSkinWidget(const std::string & _name, bool _throw = true); + ///< Get a widget defined in the inner skin of this window. + }; + +} + +#endif + diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index 2e66a4805c..781c427ef4 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -2,6 +2,8 @@ #include "../mwbase/windowmanager.hpp" +#include "exposedwindow.hpp" + using namespace MWGui; WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) @@ -9,6 +11,9 @@ WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::Win { MyGUI::WindowPtr t = static_cast(mMainWidget); t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed); + + ExposedWindow* window = static_cast(mMainWidget); + mPinButton = window->getSkinWidget ("Button"); } void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName) @@ -16,6 +21,12 @@ void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std: if ("PinToggle" == eventName) { mPinned = !mPinned; + + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); + onPinToggled(); } diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index c577564c79..7426b16fcf 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -19,6 +19,7 @@ namespace MWGui protected: virtual void onPinToggled() = 0; + MyGUI::Widget* mPinButton; bool mPinned; bool mVisible; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 39f7d07767..1dc11f2c44 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -52,6 +52,7 @@ #include "enchantingdialog.hpp" #include "trainingwindow.hpp" #include "imagebutton.hpp" +#include "exposedwindow.hpp" using namespace MWGui; @@ -127,6 +128,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 3a60916f7f..88cc5638d3 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_map_window.layout b/files/mygui/openmw_map_window.layout index b5479b6761..d4b87e60d1 100644 --- a/files/mygui/openmw_map_window.layout +++ b/files/mygui/openmw_map_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_spell_window.layout b/files/mygui/openmw_spell_window.layout index d489f41b8a..6c6629605b 100644 --- a/files/mygui/openmw_spell_window.layout +++ b/files/mygui/openmw_spell_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index c2c8a5daea..55ee7b9dac 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index a9eb23d68a..72b6861254 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -8,6 +8,18 @@ + + + + + + + + + + + + @@ -473,7 +485,7 @@ - + From 2dea86bbc7cb8b95415d626d1a8b90de894e1416 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Feb 2013 03:04:38 +0100 Subject: [PATCH 0393/1483] Make the "lock window" button appealing --- files/mygui/openmw_windows.skin.xml | 116 ++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 8 deletions(-) diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 72b6861254..93aa8fd209 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -8,17 +8,117 @@ - - - - + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -485,7 +585,7 @@ - + From 3dc28baa287dd9d2169bace23bf89d2cb792e084 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Feb 2013 16:29:38 +0100 Subject: [PATCH 0394/1483] Remove "PinToggle" event from layout file --- apps/openmw/mwgui/window_pinnable_base.cpp | 24 ++++++++-------------- apps/openmw/mwgui/window_pinnable_base.hpp | 2 +- files/mygui/openmw_windows.skin.xml | 4 +--- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index 781c427ef4..651b3a1e98 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -9,26 +9,20 @@ using namespace MWGui; WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) { - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed); - ExposedWindow* window = static_cast(mMainWidget); mPinButton = window->getSkinWidget ("Button"); + + mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); } -void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName) +void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) { - if ("PinToggle" == eventName) - { - mPinned = !mPinned; + mPinned = !mPinned; - if (mPinned) - mPinButton->changeWidgetSkin ("PinDown"); - else - mPinButton->changeWidgetSkin ("PinUp"); + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); - onPinToggled(); - } - - eventDone(this); + onPinToggled(); } diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index 7426b16fcf..50259858e2 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -14,7 +14,7 @@ namespace MWGui bool pinned() { return mPinned; } private: - void onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName); + void onPinButtonClicked(MyGUI::Widget* _sender); protected: virtual void onPinToggled() = 0; diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 93aa8fd209..73f68e80dc 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -585,9 +585,7 @@ - - - + From f4749f10dadaf119fad8b3b85e0d74a23d72e781 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Feb 2013 05:35:52 +0100 Subject: [PATCH 0395/1483] NIF bullet loader fix for incorrect collision shapes (credit goes to Chris, he asked me to push this) --- components/nifbullet/bullet_nif_loader.cpp | 134 ++++++--------------- components/nifbullet/bullet_nif_loader.hpp | 18 +-- 2 files changed, 46 insertions(+), 106 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 9c6dafa34a..a619bdda23 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -43,25 +43,14 @@ http://www.gnu.org/licenses/ . typedef unsigned char ubyte; -using namespace NifBullet; - +namespace NifBullet +{ ManualBulletShapeLoader::~ManualBulletShapeLoader() { } -btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 const &m) -{ - Ogre::Quaternion oquat(m); - btQuaternion quat; - quat.setW(oquat.w); - quat.setX(oquat.x); - quat.setY(oquat.y); - quat.setZ(oquat.z); - return quat; -} - btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) { return btVector3(v[0], v[1], v[2]); @@ -90,7 +79,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - // The first record is assumed to be the root node Nif::Record *r = nif.getRecord(0); assert(r != NULL); @@ -106,13 +94,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool hasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(node,0,NULL,hasCollisionNode,false,false); + handleNode(node,0,hasCollisionNode,false,false); //if collide = false, then it does a second pass which create a shape for raycasting. if(cShape->mCollide == false) - { - handleNode(node,0,NULL,hasCollisionNode,false,true); - } + handleNode(node,0,hasCollisionNode,false,true); //cShape->collide = hasCollisionNode&&cShape->collide; @@ -129,9 +115,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) delete m_meshInterface; } }; + if(mBoundingBox != NULL) cShape->Shape = mBoundingBox; - else { currentShape = new TriangleMeshShape(mTriMesh,true); @@ -141,34 +127,30 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) { - if (node->recType == Nif::RC_NiNode) + if(node->recType == Nif::RC_RootCollisionNode) + return true; + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; ichildren; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) + if(!list[i].empty()) { - if(hasRootCollisionNode(list[i].getPtr())) return true;; + if(hasRootCollisionNode(list[i].getPtr())) + return true; } } } - else if (node->recType == Nif::RC_NiTriShape) - { - return false; - } - else if(node->recType == Nif::RC_RootCollisionNode) - { - return true; - } return false; } -void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) +void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, + bool hasCollisionNode, bool isCollisionNode, + bool raycastingOnly) { - // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. flags |= node->flags; @@ -209,70 +191,36 @@ void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, } } - Nif::Transformation childTrafo = node->trafo; - - if (parentTrafo) - { - - // Get a non-const reference to the node's data, since we're - // overwriting it. TODO: Is this necessary? - - // For both position and rotation we have that: - // final_vector = old_vector + old_rotation*new_vector*old_scale - childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale; - - // Merge the rotations together - childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation; - - // Scale - childTrafo.scale *= parentTrafo->scale; - - } - if(node->hasBounds) { - - - btVector3 boxsize = getbtVector(node->boundXYZ); cShape->boxTranslation = node->boundPos; cShape->boxRotation = node->boundRot; - - mBoundingBox = new btBoxShape(boxsize); + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); } - - // For NiNodes, loop through children - if (node->recType == Nif::RC_NiNode) - { - Nif::NodeList const &list = ((Nif::NiNode const *)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) + if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->mCollide = !(flags&0x800); - handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); + handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); } - else if(node->recType == Nif::RC_RootCollisionNode) + + // For NiNodes, loop through children + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_RootCollisionNode); + + const Nif::NodeList &list = ninode->children; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) - handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly); + if(!list[i].empty()) + handleNode(list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycastingOnly); } } } -void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, - bool raycastingOnly) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, + bool raycastingOnly) { assert(shape != NULL); @@ -296,18 +244,14 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int return; - Nif::NiTriShapeData *data = shape->data.getPtr(); - + const Nif::NiTriShapeData *data = shape->data.getPtr(); 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 * parentScale; - short* triangles = &data->triangles[0]; + const short *triangles = &data->triangles[0]; for(size_t i = 0;i < data->triangles.size();i+=3) { - 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; + Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; + Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; + Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } @@ -320,3 +264,5 @@ void ManualBulletShapeLoader::load(const std::string &name,const std::string &gr return; OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this); } + +} // namespace NifBullet diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index 520878ce1c..0629b208de 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -51,19 +51,18 @@ namespace NifBullet class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader { public: - ManualBulletShapeLoader():resourceGroup("General"){} virtual ~ManualBulletShapeLoader(); - void warn(std::string msg) + void warn(const std::string &msg) { std::cerr << "NIFLoader: Warn:" << msg << "\n"; } - void fail(std::string msg) + void fail(const std::string &msg) { std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - assert(1); + abort(); } /** @@ -79,31 +78,26 @@ public: void load(const std::string &name,const std::string &group); private: - btQuaternion getbtQuat(Ogre::Matrix3 const &m); - btVector3 getbtVector(Ogre::Vector3 const &v); /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); + void handleNode(Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycastingOnly); /** *Helper function */ - bool hasRootCollisionNode(Nif::Node const * node); + bool hasRootCollisionNode(const Nif::Node *node); /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycastingOnly); std::string resourceName; std::string resourceGroup; - - OEngine::Physic::BulletShape* cShape;//current shape btTriangleMesh *mTriMesh; btBoxShape *mBoundingBox; From 6ae00be8a32966c2f7a9f433464e565a70f488db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 22:28:15 -0800 Subject: [PATCH 0396/1483] Fix nifbullet shape transformation --- components/nifbullet/bullet_nif_loader.cpp | 134 ++++++--------------- components/nifbullet/bullet_nif_loader.hpp | 18 +-- 2 files changed, 46 insertions(+), 106 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 9c6dafa34a..a619bdda23 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -43,25 +43,14 @@ http://www.gnu.org/licenses/ . typedef unsigned char ubyte; -using namespace NifBullet; - +namespace NifBullet +{ ManualBulletShapeLoader::~ManualBulletShapeLoader() { } -btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 const &m) -{ - Ogre::Quaternion oquat(m); - btQuaternion quat; - quat.setW(oquat.w); - quat.setX(oquat.x); - quat.setY(oquat.y); - quat.setZ(oquat.z); - return quat; -} - btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) { return btVector3(v[0], v[1], v[2]); @@ -90,7 +79,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - // The first record is assumed to be the root node Nif::Record *r = nif.getRecord(0); assert(r != NULL); @@ -106,13 +94,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool hasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(node,0,NULL,hasCollisionNode,false,false); + handleNode(node,0,hasCollisionNode,false,false); //if collide = false, then it does a second pass which create a shape for raycasting. if(cShape->mCollide == false) - { - handleNode(node,0,NULL,hasCollisionNode,false,true); - } + handleNode(node,0,hasCollisionNode,false,true); //cShape->collide = hasCollisionNode&&cShape->collide; @@ -129,9 +115,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) delete m_meshInterface; } }; + if(mBoundingBox != NULL) cShape->Shape = mBoundingBox; - else { currentShape = new TriangleMeshShape(mTriMesh,true); @@ -141,34 +127,30 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) { - if (node->recType == Nif::RC_NiNode) + if(node->recType == Nif::RC_RootCollisionNode) + return true; + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; ichildren; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) + if(!list[i].empty()) { - if(hasRootCollisionNode(list[i].getPtr())) return true;; + if(hasRootCollisionNode(list[i].getPtr())) + return true; } } } - else if (node->recType == Nif::RC_NiTriShape) - { - return false; - } - else if(node->recType == Nif::RC_RootCollisionNode) - { - return true; - } return false; } -void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) +void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, + bool hasCollisionNode, bool isCollisionNode, + bool raycastingOnly) { - // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. flags |= node->flags; @@ -209,70 +191,36 @@ void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, } } - Nif::Transformation childTrafo = node->trafo; - - if (parentTrafo) - { - - // Get a non-const reference to the node's data, since we're - // overwriting it. TODO: Is this necessary? - - // For both position and rotation we have that: - // final_vector = old_vector + old_rotation*new_vector*old_scale - childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale; - - // Merge the rotations together - childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation; - - // Scale - childTrafo.scale *= parentTrafo->scale; - - } - if(node->hasBounds) { - - - btVector3 boxsize = getbtVector(node->boundXYZ); cShape->boxTranslation = node->boundPos; cShape->boxRotation = node->boundRot; - - mBoundingBox = new btBoxShape(boxsize); + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); } - - // For NiNodes, loop through children - if (node->recType == Nif::RC_NiNode) - { - Nif::NodeList const &list = ((Nif::NiNode const *)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) + if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->mCollide = !(flags&0x800); - handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); + handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); } - else if(node->recType == Nif::RC_RootCollisionNode) + + // For NiNodes, loop through children + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_RootCollisionNode); + + const Nif::NodeList &list = ninode->children; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) - handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly); + if(!list[i].empty()) + handleNode(list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycastingOnly); } } } -void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, - bool raycastingOnly) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, + bool raycastingOnly) { assert(shape != NULL); @@ -296,18 +244,14 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int return; - Nif::NiTriShapeData *data = shape->data.getPtr(); - + const Nif::NiTriShapeData *data = shape->data.getPtr(); 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 * parentScale; - short* triangles = &data->triangles[0]; + const short *triangles = &data->triangles[0]; for(size_t i = 0;i < data->triangles.size();i+=3) { - 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; + Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; + Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; + Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } @@ -320,3 +264,5 @@ void ManualBulletShapeLoader::load(const std::string &name,const std::string &gr return; OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this); } + +} // namespace NifBullet diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index 520878ce1c..0629b208de 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -51,19 +51,18 @@ namespace NifBullet class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader { public: - ManualBulletShapeLoader():resourceGroup("General"){} virtual ~ManualBulletShapeLoader(); - void warn(std::string msg) + void warn(const std::string &msg) { std::cerr << "NIFLoader: Warn:" << msg << "\n"; } - void fail(std::string msg) + void fail(const std::string &msg) { std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - assert(1); + abort(); } /** @@ -79,31 +78,26 @@ public: void load(const std::string &name,const std::string &group); private: - btQuaternion getbtQuat(Ogre::Matrix3 const &m); - btVector3 getbtVector(Ogre::Vector3 const &v); /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); + void handleNode(Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycastingOnly); /** *Helper function */ - bool hasRootCollisionNode(Nif::Node const * node); + bool hasRootCollisionNode(const Nif::Node *node); /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycastingOnly); std::string resourceName; std::string resourceGroup; - - OEngine::Physic::BulletShape* cShape;//current shape btTriangleMesh *mTriMesh; btBoxShape *mBoundingBox; From cfdc820a1f6382be2c78c0a71f20fa2e7f893cd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 01:55:12 -0800 Subject: [PATCH 0397/1483] Make an actor fly when it has a levitate effect --- apps/openmw/mwworld/worldimp.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1a6630232d..e75bd16778 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -12,6 +12,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" @@ -886,12 +888,14 @@ namespace MWWorld player = iter; continue; } - Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, !isSwimming(iter->first)); + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, + !isSwimming(iter->first) && !isFlying(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { - Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, + !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } // the only purpose this has currently is to update the debug drawer @@ -1386,11 +1390,15 @@ namespace MWWorld World::isFlying(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - /// \todo check for levitation effects const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(physactor && physactor->getCollisionMode()) - return false; - return true; + if(!physactor || !physactor->getCollisionMode()) + return true; + + const MWWorld::Class &cls = MWWorld::Class::get(ptr); + if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) + return true; + + return false; } bool From 617158afcd43efc533fb49e07e736df60fcf6696 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 02:32:48 -0800 Subject: [PATCH 0398/1483] Ensure updated skeleton bone placement matches in world space Objects attached to actors (shirts, robes, etc) do not require the same node hierarchy as the character root. So to ensure proper placement, we need to set the bone target's derived transformation using the source bone's derived transformation (which in turn means we need to work up from the root, to ensure the bone's parents are properly placed). --- apps/openmw/mwrender/animation.cpp | 42 +++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3300454231..f4b618866a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -197,19 +197,41 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } +static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) +{ + if(skelsrc->hasBone(bone->getName())) + { + Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); + if(!srcbone->getParent() || !bone->getParent()) + { + bone->setOrientation(srcbone->getOrientation()); + bone->setPosition(srcbone->getPosition()); + bone->setScale(srcbone->getScale()); + } + else + { + bone->_setDerivedOrientation(srcbone->_getDerivedOrientation()); + bone->_setDerivedPosition(srcbone->_getDerivedPosition()); + bone->setScale(Ogre::Vector3::UNIT_SCALE); + } + } + else + { + // No matching bone in the source. Make sure it stays properly offset + // from its parent. + bone->resetToInitialState(); + } + + Ogre::Node::ChildNodeIterator boneiter = bone->getChildIterator(); + while(boneiter.hasMoreElements()) + updateBoneTree(skelsrc, static_cast(boneiter.getNext())); +} + void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel) { - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::Skeleton::BoneIterator boneiter = skel->getRootBoneIterator(); while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - if(!skelsrc->hasBone(bone->getName())) - continue; - Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); - bone->setOrientation(srcbone->getOrientation()); - bone->setPosition(srcbone->getPosition()); - bone->setScale(srcbone->getScale()); - } + updateBoneTree(skelsrc, boneiter.getNext()); } From fe6fa9ebe745ca2bb2cbe2b70e82eb150a50575d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 04:14:52 -0800 Subject: [PATCH 0399/1483] Simplify newtrace a bit --- apps/openmw/mwworld/physicssystem.cpp | 15 ++++---- libs/openengine/bullet/trace.cpp | 51 ++++++--------------------- libs/openengine/bullet/trace.h | 2 +- 3 files changed, 18 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5552bd7497..0b9e13fb7a 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -34,18 +34,18 @@ namespace MWWorld { private: static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, - float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior, + const Ogre::Vector3 &halfExtents, bool isInterior, OEngine::Physic::PhysicEngine *engine) { traceResults trace; // no initialization needed newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, - halfExtents, verticalRotation, isInterior, engine); + halfExtents, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. @@ -105,7 +105,6 @@ namespace MWWorld bool onground = false; float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); Ogre::Vector3 velocity; @@ -120,7 +119,7 @@ namespace MWWorld { if(!(movement.z > 0.0f)) { - newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, isInterior, engine); if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) onground = true; } @@ -145,7 +144,7 @@ namespace MWWorld int iterations = 0; do { // trace to where character would go if there were no obstructions - newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; currentNormal = trace.planenormal; remainingTime = remainingTime * (1.0f-trace.fraction); @@ -157,7 +156,7 @@ namespace MWWorld if(getSlope(currentNormal) > sMaxSlope || currentNormal == lastNormal) { if((gravity && !onground) || - !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + !stepMove(newPosition, velocity, remainingTime, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); resultantDirection.normalise(); @@ -182,7 +181,7 @@ namespace MWWorld if(onground) { - newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, isInterior, engine); if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) newPosition.z = trace.endpos.z + 2.0f; else diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 2f52d669a4..7664eb418e 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -24,21 +24,11 @@ enum collaborativePhysicsType Both_Physics = 3 // This object has both kinds of physics (example: activators) }; -struct NewPhysTraceResults -{ - Ogre::Vector3 endPos; - Ogre::Vector3 hitNormal; - float fraction; - //const Object* hitObj; -}; - -static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, - OEngine::Physic::PhysicEngine* enginePass) +void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine *enginePass) //Traceobj was a Aedra Object { const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); - const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z + const btQuaternion btrot(0.0f, 0.0f, 0.0f); //y, x, z const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); @@ -46,43 +36,22 @@ static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& const btTransform to(btrot, btend); btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); - newTraceCallback.m_collisionFilterMask = Only_Collision; enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); // Copy the hit data over to our trace results struct: - out->fraction = newTraceCallback.m_closestHitFraction; - - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; - out->hitNormal.x = tracehitnormal.x(); - out->hitNormal.y = tracehitnormal.y(); - out->hitNormal.z = tracehitnormal.z(); - - const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; - out->endPos.x = tracehitpos.x(); - out->endPos.y = tracehitpos.y(); - out->endPos.z = tracehitpos.z(); - - return newTraceCallback.hasHit(); -} - - -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object -{ - NewPhysTraceResults out; - bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), - isInterior, enginePass); - if(!hasHit) + if(newTraceCallback.hasHit()) + { + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + results->fraction = newTraceCallback.m_closestHitFraction; + results->planenormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + results->endpos = (end-start)*results->fraction + start; + } + else { results->endpos = end; results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); results->fraction = 1.0f; } - else - { - results->fraction = out.fraction; - results->planenormal = out.hitNormal; - results->endpos = (end-start)*results->fraction + start; - } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 34ecb7454c..f484497d97 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -21,6 +21,6 @@ struct traceResults float fraction; }; -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); +void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); #endif From b14def7c0951fc17eff0394be34304dcf6223ad2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 05:24:38 -0800 Subject: [PATCH 0400/1483] Set the character as being on the ground when colliding with a shallow enough slope --- apps/openmw/mwworld/physicssystem.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 0b9e13fb7a..a61eebe2fc 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -137,45 +137,43 @@ namespace MWWorld clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + const Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; int iterations = 0; do { // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; - currentNormal = trace.planenormal; remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + if(getSlope(trace.planenormal) <= sMaxSlope) { + // We hit a slope we can walk on. Update velocity accordingly. + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + // We're only on the ground if gravity is affecting us + onground = gravity; + } + else + { + // Can't walk on this. Try to step up onto it. if((gravity && !onground) || !stepMove(newPosition, velocity, remainingTime, halfExtents, isInterior, engine)) { - Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); + Ogre::Vector3 resultantDirection = trace.planenormal.crossProduct(up); resultantDirection.normalise(); clippedVelocity = velocity; projectVelocity(clippedVelocity, resultantDirection); // just this isn't enough sometimes. It's the same problem that causes steps to be necessary on even uphill terrain. - clippedVelocity += currentNormal*clippedVelocity.length()/50.0f; - //std::cout<< "clipped velocity: "< 0.0f); From 4eb8ea0c954740e2287c1c6c81b2a11fc2e11eca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 07:51:36 -0800 Subject: [PATCH 0401/1483] Fix stepping and vertical force accumulation --- apps/openmw/mwworld/physicssystem.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a61eebe2fc..9b9c9afea2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -39,14 +39,18 @@ namespace MWWorld { traceResults trace; // no initialization needed - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), - position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, - halfExtents, isInterior, engine); + newtrace(&trace, position, position+Ogre::Vector3(0.0f,0.0f,sStepSize), + halfExtents, isInterior, engine); + if(trace.fraction == 0.0f) + return false; + + newtrace(&trace, trace.endpos, trace.endpos + velocity*remainingTime, + halfExtents, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); - if(getSlope(trace.planenormal) < sMaxSlope) + if(getSlope(trace.planenormal) <= sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. position = trace.endpos; @@ -56,7 +60,7 @@ namespace MWWorld return false; } - static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce) + static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce=1.0f) { //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. @@ -134,7 +138,7 @@ namespace MWWorld { // if we're on the ground, force velocity to track it clippedVelocity.z = velocity.z = std::max(0.0f, velocity.z); - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal); } const Ogre::Vector3 up(0.0f, 0.0f, 1.0f); @@ -153,7 +157,7 @@ namespace MWWorld if(getSlope(trace.planenormal) <= sMaxSlope) { // We hit a slope we can walk on. Update velocity accordingly. - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal); // We're only on the ground if gravity is affecting us onground = gravity; } @@ -186,7 +190,7 @@ namespace MWWorld onground = false; } physicActor->setOnGround(onground); - physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); + physicActor->setVerticalForce(clippedVelocity.z - time*627.2f); return newPosition; } From 18d01cd65a585abbaf1b7f197d2af283f922c7a8 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Wed, 20 Feb 2013 19:27:04 +0100 Subject: [PATCH 0402/1483] Implemented a first-run dialog to import Morrowind.ini settings --- apps/launcher/main.cpp | 166 +------- apps/launcher/maindialog.cpp | 427 +++++++++++++++++--- apps/launcher/maindialog.hpp | 31 +- apps/launcher/settings/gamesettings.cpp | 34 +- apps/launcher/settings/gamesettings.hpp | 5 + apps/launcher/utils/checkablemessagebox.cpp | 43 +- apps/launcher/utils/checkablemessagebox.hpp | 43 +- 7 files changed, 493 insertions(+), 256 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index ba84518c1e..5d57dce551 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,23 +1,6 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include #include "maindialog.hpp" -#include "settings/gamesettings.hpp" -#include "settings/graphicssettings.hpp" -#include "settings/launchersettings.hpp" - int main(int argc, char *argv[]) { @@ -45,154 +28,7 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); - // Create setting file handlers - - Files::ConfigurationManager cfgMgr; - QString userPath = QString::fromStdString(cfgMgr.getUserPath().string()); - QString globalPath = QString::fromStdString(cfgMgr.getGlobalPath().string()); - - GameSettings gameSettings(cfgMgr); - GraphicsSettings graphicsSettings; - LauncherSettings launcherSettings; - - QStringList paths; - paths.append(userPath + QString("openmw.cfg")); - paths.append(QString("openmw.cfg")); - paths.append(globalPath + QString("openmw.cfg")); - - foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; - QFile file(path); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error opening OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - return 0; - } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - gameSettings.readFile(stream); - } - file.close(); - } - - if (gameSettings.getDataDirs().isEmpty()) - { - QMessageBox msgBox; - msgBox.setWindowTitle("Error detecting Morrowind installation"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(QObject::tr("
Could not find the Data Files location

\ - The directory containing the data files was not found.

\ - Press \"Browse...\" to specify the location manually.
")); - - QAbstractButton *dirSelectButton = - msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); - - msgBox.exec(); - - QString selectedFile; - if (msgBox.clickedButton() == dirSelectButton) { - selectedFile = QFileDialog::getOpenFileName( - NULL, - QObject::tr("Select master file"), - QDir::currentPath(), - QString("Morrowind master file (*.esm)")); - } - - if (selectedFile.isEmpty()) - return 0; // Cancel was clicked; - - qDebug() << selectedFile; - QFileInfo info(selectedFile); - - // Add the new dir to the settings file and to the data dir container - gameSettings.setValue(QString("data"), info.absolutePath()); - gameSettings.addDataDir(info.absolutePath()); - - } - - // On to the graphics settings - QFile localDefault(QString("settings-default.cfg")); - QFile globalDefault(globalPath + QString("settings-default.cfg")); - - if (!localDefault.exists() && !globalDefault.exists()) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error reading OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not find settings-default.cfg

\ - The problem may be due to an incomplete installation of OpenMW.
\ - Reinstalling OpenMW may resolve the problem.")); - msgBox.exec(); - return 0; - } - - paths.clear(); - paths.append(globalPath + QString("settings-default.cfg")); - paths.append(QString("settings-default.cfg")); - paths.append(userPath + QString("settings.cfg")); - - foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; - QFile file(path); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error opening OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - return 0; - } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - graphicsSettings.readFile(stream); - } - file.close(); - } - - // Now the launcher settings - paths.clear(); - paths.append(QString("launcher.cfg")); - paths.append(userPath + QString("launcher.cfg")); - - foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; - QFile file(path); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error opening OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - return 0; - } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - launcherSettings.readFile(stream); - } - file.close(); - } - - - MainDialog mainWin(gameSettings, graphicsSettings, launcherSettings); + MainDialog mainWin; if (mainWin.setup()) { mainWin.show(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 15f2690dad..77526677b8 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,9 +1,6 @@ #include -#include "settings/gamesettings.hpp" -#include "settings/graphicssettings.hpp" -#include "settings/launchersettings.hpp" - +#include "utils/checkablemessagebox.hpp" #include "utils/profilescombobox.hpp" #include "maindialog.hpp" @@ -11,13 +8,8 @@ #include "graphicspage.hpp" #include "datafilespage.hpp" -MainDialog::MainDialog(GameSettings &gameSettings, - GraphicsSettings &graphicsSettings, - LauncherSettings &launcherSettings) - : mGameSettings(gameSettings) - , mGraphicsSettings(graphicsSettings) - , mLauncherSettings(launcherSettings) - +MainDialog::MainDialog() + : mGameSettings(mCfgMgr) { QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); @@ -95,7 +87,6 @@ MainDialog::MainDialog(GameSettings &gameSettings, connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); createIcons(); - createPages(); } void MainDialog::createIcons() @@ -161,14 +152,148 @@ void MainDialog::createPages() } +bool MainDialog::showFirstRunDialog() +{ + CheckableMessageBox msgBox(this); + msgBox.setWindowTitle(tr("Morrowind installation detected")); + + QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion); + int size = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize); + msgBox.setIconPixmap(icon.pixmap(size, size)); + + + QAbstractButton *importerButton = + msgBox.addButton(tr("Import"), QDialogButtonBox::AcceptRole); // ActionRole doesn't work?! + QAbstractButton *skipButton = + msgBox.addButton(tr("Skip"), QDialogButtonBox::RejectRole); + + Q_UNUSED(skipButton); // Surpress compiler unused warning + + msgBox.setStandardButtons(QDialogButtonBox::NoButton); + + msgBox.setText(tr("
An existing Morrowind installation was detected

\ + Would you like to import settings from Morrowind.ini?
")); + + msgBox.setCheckBoxText(tr("Include selected masters and plugins (creates a new profile)")); + msgBox.exec(); + + + if (msgBox.clickedButton() == importerButton) { + + QString iniPath; + + foreach (const QString &path, mGameSettings.getDataDirs()) { + QDir dir(path); + dir.setPath(dir.canonicalPath()); // Resolve symlinks + + if (!dir.cdUp()) + continue; // Cannot move from Data Files + + if (dir.exists(QString("Morrowind.ini"))) + iniPath = dir.absoluteFilePath(QString("Morrowind.ini")); + } + + if (iniPath.isEmpty()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error reading Morrowind configuration file")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not find Morrowind.ini

\ + The problem may be due to an incomplete installation of Morrowind.
\ + Reinstalling Morrowind may resolve the problem.")); + msgBox.exec(); + return false; + } + + // Create the file if it doesn't already exist, else the importer will fail + QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg"); + QFile file(path); + + if (!file.exists()) { + if (!file.open(QIODevice::ReadWrite)) { + // File cannot be created + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0 for writing

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return false; + } + + file.close(); + } + + // Construct the arguments to run the importer + QStringList arguments; + + if (msgBox.isChecked()) + arguments.append(QString("-g")); + + arguments.append(iniPath); + arguments.append(path); + + if (!startProgram(QString("mwiniimport"), arguments, false)) + return false; + + // Re-read the game settings + mGameSettings.clear(); + + if (!setupGameSettings()) + return false; + + // Add a new profile + if (msgBox.isChecked()) { + qDebug() << "add a new profile"; + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), QString("Imported")); + + mLauncherSettings.remove(QString("Profiles/Imported/master")); + mLauncherSettings.remove(QString("Profiles/Imported/plugin")); + + QStringList masters = mGameSettings.values(QString("master")); + QStringList plugins = mGameSettings.values(QString("plugin")); + + foreach (const QString &master, masters) { + mLauncherSettings.setMultiValue(QString("Profiles/Imported/master"), master); + } + + foreach (const QString &plugin, plugins) { + mLauncherSettings.setMultiValue(QString("Profiles/Imported/plugin"), plugin); + } + } + + } + + return true; +} bool MainDialog::setup() { - // Call this so we can exit on Ogre errors before mainwindow is shown - if (!mGraphicsPage->setupOgre()) { + if (!setupLauncherSettings()) return false; + + if (!setupGameSettings()) + return false; + + if (!setupGraphicsSettings()) + return false; + + // Check if we need to show the importer + if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true")) + { + if (!showFirstRunDialog()) + return false; } + // Now create the pages as they need the settings + createPages(); + + // Call this so we can exit on Ogre errors before mainwindow is shown + if (!mGraphicsPage->setupOgre()) + return false; + loadSettings(); return true; } @@ -181,6 +306,164 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) mPagesWidget->setCurrentIndex(mIconWidget->row(current)); } +bool MainDialog::setupLauncherSettings() +{ + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + + QStringList paths; + paths.append(QString("launcher.cfg")); + paths.append(userPath + QString("launcher.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return false; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mLauncherSettings.readFile(stream); + } + file.close(); + } + + return true; +} + +bool MainDialog::setupGameSettings() +{ + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); + + QStringList paths; + paths.append(userPath + QString("openmw.cfg")); + paths.append(QString("openmw.cfg")); + paths.append(globalPath + QString("openmw.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return false; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mGameSettings.readFile(stream); + } + file.close(); + } + + if (mGameSettings.getDataDirs().isEmpty()) + { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error detecting Morrowind installation")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(QObject::tr("
Could not find the Data Files location

\ + The directory containing the data files was not found.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + QString selectedFile; + if (msgBox.clickedButton() == dirSelectButton) { + selectedFile = QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select master file"), + QDir::currentPath(), + QString(tr("Morrowind master file (*.esm)"))); + } + + if (selectedFile.isEmpty()) + return false; // Cancel was clicked; + + qDebug() << selectedFile; + QFileInfo info(selectedFile); + + // Add the new dir to the settings file and to the data dir container + mGameSettings.setValue(QString("data"), info.absolutePath()); + mGameSettings.addDataDir(info.absolutePath()); + + } + + return true; +} + +bool MainDialog::setupGraphicsSettings() +{ + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); + + QFile localDefault(QString("settings-default.cfg")); + QFile globalDefault(globalPath + QString("settings-default.cfg")); + + if (!localDefault.exists() && !globalDefault.exists()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error reading OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not find settings-default.cfg

\ + The problem may be due to an incomplete installation of OpenMW.
\ + Reinstalling OpenMW may resolve the problem.")); + msgBox.exec(); + return false; + } + + + QStringList paths; + paths.append(globalPath + QString("settings-default.cfg")); + paths.append(QString("settings-default.cfg")); + paths.append(userPath + QString("settings.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return false; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mGraphicsSettings.readFile(stream); + } + file.close(); + } + + return true; +} + void MainDialog::loadSettings() { int width = mLauncherSettings.value(QString("General/MainWindow/width")).toInt(); @@ -206,6 +489,9 @@ void MainDialog::saveSettings() mLauncherSettings.setValue(QString("General/MainWindow/posx"), posX); mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY); + + mLauncherSettings.setValue(QString("General/firstrun"), QString("false")); + } void MainDialog::writeSettings() @@ -221,7 +507,7 @@ void MainDialog::writeSettings() if (!dir.exists()) { if (!dir.mkpath(userPath)) { QMessageBox msgBox; - msgBox.setWindowTitle("Error creating OpenMW configuration directory"); + msgBox.setWindowTitle(tr("Error creating OpenMW configuration directory")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not create %0

\ @@ -238,7 +524,7 @@ void MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not open or create %0 for writing

\ @@ -260,7 +546,7 @@ void MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not open or create %0 for writing

\ @@ -282,7 +568,7 @@ void MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created QMessageBox msgBox; - msgBox.setWindowTitle("Error writing Launcher configuration file"); + msgBox.setWindowTitle(tr("Error writing Launcher configuration file")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not open or create %0 for writing

\ @@ -308,69 +594,108 @@ void MainDialog::closeEvent(QCloseEvent *event) void MainDialog::play() { - // First do a write of all the configs, just to be sure - //mDataFilesPage->writeConfig(); - //mGraphicsPage->writeConfig(); saveSettings(); writeSettings(); + // Launch the game detached + startProgram(QString("openmw"), true); + qApp->quit(); +} + +bool MainDialog::startProgram(const QString &name, const QStringList &arguments, bool detached) +{ + QString path = name; #ifdef Q_OS_WIN - QString game = "./openmw.exe"; - QFile file(game); + path.append(QString(".exe")); #elif defined(Q_OS_MAC) QDir dir(QCoreApplication::applicationDirPath()); - QString game = dir.absoluteFilePath("openmw"); - QFile file(game); - game = "\"" + game + "\""; + path = dir.absoluteFilePath(name); #else - QString game = "./openmw"; - QFile file(game); + path.prepend(QString("./")); #endif + QFile file(path); + QProcess process; QFileInfo info(file); if (!file.exists()) { QMessageBox msgBox; - msgBox.setWindowTitle("Error starting OpenMW"); + msgBox.setWindowTitle(tr("Error starting executable")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not find OpenMW

\ - The OpenMW application is not found.
\ - Please make sure OpenMW is installed correctly and try again.
")); + msgBox.setText(tr("
Could not find %1

\ + The application is not found.
\ + Please make sure OpenMW is installed correctly and try again.
").arg(info.fileName())); msgBox.exec(); - return; + return false; } if (!info.isExecutable()) { QMessageBox msgBox; - msgBox.setWindowTitle("Error starting OpenMW"); + msgBox.setWindowTitle(tr("Error starting executable")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not start OpenMW

\ - The OpenMW application is not executable.
\ - Please make sure you have the right permissions and try again.
")); + msgBox.setText(tr("
Could not start %1

\ + The application is not executable.
\ + Please make sure you have the right permissions and try again.
").arg(info.fileName())); msgBox.exec(); - return; + return false; } - // Start the game - if (!process.startDetached(game)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error starting OpenMW"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not start OpenMW

\ - An error occurred while starting OpenMW.

\ - Press \"Show Details...\" for more information.
")); - msgBox.setDetailedText(process.errorString()); - msgBox.exec(); + // Start the executable + if (detached) { + if (!process.startDetached(path, arguments)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error starting executable")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not start %1

\ + An error occurred while starting %1.

\ + Press \"Show Details...\" for more information.
").arg(info.fileName())); + msgBox.setDetailedText(process.errorString()); + msgBox.exec(); - return; + return false; + } } else { - qApp->quit(); + process.start(path, arguments); + if (!process.waitForFinished()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error starting executable")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not start %1

\ + An error occurred while starting %1.

\ + Press \"Show Details...\" for more information.
").arg(info.fileName())); + msgBox.setDetailedText(process.errorString()); + msgBox.exec(); + + return false; + } + + if (process.exitCode() != 0) { + QString error(process.readAllStandardError()); + error.append(tr("\nArguments:\n")); + error.append(arguments.join(" ")); + + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error running executable")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Executable %1 returned an error

\ + An error occurred while running %1.

\ + Press \"Show Details...\" for more information.
").arg(info.fileName())); + msgBox.setDetailedText(error); + msgBox.exec(); + + return false; + } } + + return true; + } diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 7167d101db..f221bd5e69 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -5,6 +5,10 @@ #include +#include "settings/gamesettings.hpp" +#include "settings/graphicssettings.hpp" +#include "settings/launchersettings.hpp" + class QListWidget; class QListWidgetItem; class QStackedWidget; @@ -16,20 +20,20 @@ class PlayPage; class GraphicsPage; class DataFilesPage; -class GameSettings; -class GraphicsSettings; -class LauncherSettings; - class MainDialog : public QMainWindow { Q_OBJECT public: - MainDialog(GameSettings &gameSettings, - GraphicsSettings &GraphicsSettings, - LauncherSettings &launcherSettings); + MainDialog(); + + +// GameSettings &gameSettings, +// GraphicsSettings &GraphicsSettings, +// LauncherSettings &launcherSettings); bool setup(); + bool showFirstRunDialog(); public slots: void changePage(QListWidgetItem *current, QListWidgetItem *previous); @@ -39,10 +43,17 @@ private: void createIcons(); void createPages(); + bool setupLauncherSettings(); + bool setupGameSettings(); + bool setupGraphicsSettings(); + void loadSettings(); void saveSettings(); void writeSettings(); + inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); } + bool startProgram(const QString &name, const QStringList &arguments, bool detached = false); + void closeEvent(QCloseEvent *event); QListWidget *mIconWidget; @@ -54,9 +65,9 @@ private: Files::ConfigurationManager mCfgMgr; - GameSettings &mGameSettings; - GraphicsSettings &mGraphicsSettings; - LauncherSettings &mLauncherSettings; + GameSettings mGameSettings; + GraphicsSettings mGraphicsSettings; + LauncherSettings mLauncherSettings; }; diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index fcf6f8b8a7..20ccebc97c 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -25,6 +25,7 @@ void GameSettings::validatePaths() return; QStringList paths = mSettings.values(QString("data")); + qDebug() << "paths " << paths; Files::PathContainer dataDirs; foreach (const QString &path, paths) { @@ -63,9 +64,6 @@ void GameSettings::validatePaths() if (dir.exists()) mDataLocal = path; } - qDebug() << mSettings; - - } QStringList GameSettings::values(const QString &key, const QStringList &defaultValues) @@ -91,18 +89,24 @@ bool GameSettings::readFile(QTextStream &stream) QString key = keyRe.cap(1).simplified(); QString value = keyRe.cap(2).simplified(); - // There can be multiple keys - if (key == QLatin1String("data") || - key == QLatin1String("master") || - key == QLatin1String("plugin")) - { - // Remove keys from previous config and overwrite them - mSettings.remove(key); - QStringList values = cache.values(key); - if (!values.contains(value)) // Do not insert duplicate values - cache.insertMulti(key, value); - } else { - cache.insert(key, value); +// // There can be multiple keys +// if (key == QLatin1String("data") || +// key == QLatin1String("master") || +// key == QLatin1String("plugin")) +// { +// // Remove keys from previous config and overwrite them +// mSettings.remove(key); +// QStringList values = cache.values(key); +// if (!values.contains(value)) // Do not insert duplicate values +// cache.insertMulti(key, value); +// } else { +// cache.insert(key, value); +// } + mSettings.remove(key); + + QStringList values = cache.values(key); + if (!values.contains(value)) { + cache.insertMulti(key, value); } } } diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index 8aac1552da..fa62872b06 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -41,6 +41,11 @@ public: mSettings.remove(key); } + inline void clear() + { + mSettings.clear(); + } + inline QStringList getDataDirs() { return mDataDirs; } inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } inline QString getDataLocal() {return mDataLocal; } diff --git a/apps/launcher/utils/checkablemessagebox.cpp b/apps/launcher/utils/checkablemessagebox.cpp index 8aa01d1018..990835594b 100644 --- a/apps/launcher/utils/checkablemessagebox.cpp +++ b/apps/launcher/utils/checkablemessagebox.cpp @@ -1,3 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "checkablemessagebox.hpp" + #include #include @@ -14,21 +45,17 @@ #include #include -#include "checkablemessagebox.hpp" +/*! + \class Utils::CheckableMessageBox -/* - class CheckableMessageBox - Modified from the one used in Qt Creator - - A messagebox suitable for questions with a - "Do not ask me again" checkbox. + \brief A messagebox suitable for questions with a + "Do not ask me again" checkbox. Emulates the QMessageBox API with static conveniences. The message label can open external URLs. */ - class CheckableMessageBoxPrivate { public: diff --git a/apps/launcher/utils/checkablemessagebox.hpp b/apps/launcher/utils/checkablemessagebox.hpp index ceb437d4d9..93fd43fe1f 100644 --- a/apps/launcher/utils/checkablemessagebox.hpp +++ b/apps/launcher/utils/checkablemessagebox.hpp @@ -1,3 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + #ifndef CHECKABLEMESSAGEBOX_HPP #define CHECKABLEMESSAGEBOX_HPP @@ -22,13 +51,13 @@ public: virtual ~CheckableMessageBox(); static QDialogButtonBox::StandardButton - question(QWidget *parent, - const QString &title, - const QString &question, - const QString &checkBoxText, - bool *checkBoxSetting, - QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No, - QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No); + question(QWidget *parent, + const QString &title, + const QString &question, + const QString &checkBoxText, + bool *checkBoxSetting, + QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No, + QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No); QString text() const; void setText(const QString &); From 63a13cf9cac94f8b642d61b2c9c11f193c8098ad Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Wed, 20 Feb 2013 19:29:12 +0100 Subject: [PATCH 0403/1483] Whoops, removed an include --- apps/launcher/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 5d57dce551..a5c6e30a5e 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,4 +1,5 @@ #include +#include #include "maindialog.hpp" From 7fcca180b6751249ae61c13660659501af5317cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 20:08:04 -0800 Subject: [PATCH 0404/1483] Implement rudimentary jumping --- apps/openmw/mwmechanics/character.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 713f1bb3b4..6c8d558a4d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -181,10 +181,17 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + bool onground = world->isOnGround(mPtr); bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); + // This jump is all kinds of wrong. The speed is incorrect, the state should be set to + // Jump, and X/Y movement should be disallowed except for the initial thrust (which would + // be carried by "physics" until landing). + if(onground) + movement.z += vec.z * (500.0f*duration); + if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { if(vec.x > 0.0f) From ccf5c04706100de9a163b75ec1a4612f5cfcb29c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Feb 2013 12:10:56 +0100 Subject: [PATCH 0405/1483] updated credits files --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 936f3efd9b..5c966d86b2 100644 --- a/credits.txt +++ b/credits.txt @@ -16,6 +16,7 @@ Alexander Olofsson (Ace) Artem Kotsynyak (greye) athile BrotherBrick +Chris Robinson Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) Douglas Diniz (Dgdiniz) From 56468eaecf475a14c60c8975149281e656878b3b Mon Sep 17 00:00:00 2001 From: hasufell Date: Thu, 21 Feb 2013 19:19:53 +0100 Subject: [PATCH 0406/1483] Add install rule for opencs --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfd1c7dd39..0ef85e34dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -660,6 +660,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) # Install icon and .desktop INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}") From 9b7957cf20c12c82c62c4dc7575376dd363d4c83 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Feb 2013 19:27:07 +0100 Subject: [PATCH 0407/1483] fixed a missing inlcude --- components/bsa/bsa_file.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 5e529e18e8..8db4fa8888 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -23,9 +23,7 @@ #include "bsa_file.hpp" -//#include -//#include -//#include +#include #include "../files/constrainedfiledatastream.hpp" From 82595e66b2eec8f02557d8d01162327ddaa2ef86 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 21 Feb 2013 22:47:18 +0400 Subject: [PATCH 0408/1483] another missing header for #576 --- 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 e6d3182eda..58d1bc9b85 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -37,7 +37,7 @@ //TODO: when threading is needed, enable these //#include -//#include +#include namespace Nif { From 71e5369f0457f4313be33c055886334f4ca59a07 Mon Sep 17 00:00:00 2001 From: lazydev Date: Fri, 22 Feb 2013 02:18:54 +0400 Subject: [PATCH 0409/1483] Loading translation data for all the plugin files, not only for the first one --- apps/openmw/engine.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index cb93968638..48206ba237 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -215,7 +215,7 @@ void OMW::Engine::addMaster (const std::string& master) { mMaster.push_back(master); std::string &str = mMaster.back(); - + // Append .esm if not already there std::string::size_type sep = str.find_last_of ("."); if (sep == std::string::npos) @@ -303,7 +303,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } mOgre = new OEngine::Render::OgreRenderer; - + mOgre->configure( mCfgMgr.getLogPath().string(), renderSystem, @@ -345,7 +345,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) //Load translation data mTranslationDataStorage.setEncoder(mEncoder); - mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[0]); + for (size_t i = 0; i < mMaster.size(); i++) + mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[i]); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); From 9c3af5f344497ebdacc2477565a1df78a3996f29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:26:30 -0800 Subject: [PATCH 0410/1483] Do not interpret noclip mode as flying --- apps/openmw/mwworld/worldimp.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e75bd16778..bfc313caa4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1389,15 +1389,9 @@ namespace MWWorld bool World::isFlying(const MWWorld::Ptr &ptr) const { - RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(!physactor || !physactor->getCollisionMode()) - return true; - const MWWorld::Class &cls = MWWorld::Class::get(ptr); if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) return true; - return false; } From 7ec73c29f2ff1af05df4f3aac9f86907a805fbf2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:27:26 -0800 Subject: [PATCH 0411/1483] Do not return the player's Animation object for non-players --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1551f73b83..0b9730dead 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -923,7 +923,8 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors.getAnimation(ptr); - if(!anim) anim = mPlayer->getAnimation(); + if(!anim && ptr.getRefData().getHandle() == "player") + anim = mPlayer->getAnimation(); return anim; } From 84227caa0c715922b8f3984beed92b141de23fd8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:30:06 -0800 Subject: [PATCH 0412/1483] Cleanup Npc::getSpeed a little --- apps/openmw/mwclass/npc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4a31334adf..642c7f6453 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -335,14 +335,16 @@ namespace MWClass float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); + if(npcdata->mNpcStats.isWerewolf()) + runSpeed *= fWereWolfRunMult->getFloat(); float moveSpeed; if(normalizedEncumbrance >= 1.0f) moveSpeed = 0.0f; - else if(world->isFlying(ptr)) + else if(mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + - mageffects.get(MWMechanics::EffectKey(10)).mMagnitude/*levitate*/); + mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude); flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); @@ -353,7 +355,7 @@ namespace MWClass float swimSpeed = walkSpeed; if(Npc::getStance(ptr, Run, false)) swimSpeed = runSpeed; - swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1)).mMagnitude/*swift swim*/; + swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1/*swift swim*/)).mMagnitude; swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; @@ -365,8 +367,6 @@ namespace MWClass if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) moveSpeed *= 0.75f; - if(npcdata->mNpcStats.isWerewolf() && Npc::getStance(ptr, Run, false)) - moveSpeed *= fWereWolfRunMult->getFloat(); return moveSpeed; } From 5e1ec9e128599ee95664799f871122e9db745eff Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 22 Feb 2013 08:27:00 -0800 Subject: [PATCH 0413/1483] improved book window layout --- files/mygui/openmw_book.layout | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 894c1dbeb7..96d1153f0e 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -2,41 +2,45 @@ - + - + + - + + - + - + + - + - + + - + - + - - + + From 9dee2a72cd732bc302074f9ecf7e317704da3704 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 09:22:06 -0800 Subject: [PATCH 0414/1483] Use a separate method to calculate animation velocity --- apps/openmw/mwrender/animation.cpp | 85 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f4b618866a..707aedcd93 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -175,6 +175,49 @@ void Animation::setLooping(bool loop) } +void Animation::calcAnimVelocity() +{ + const Ogre::NodeAnimationTrack *track = 0; + + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track && track->getNumKeyFrames() > 1) + { + float loopstarttime = 0.0f; + float loopstoptime = mCurrentAnim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); + while(keyiter != mCurrentKeys->end()) + { + if(keyiter->second == "loop start") + loopstarttime = keyiter->first; + else if(keyiter->second == "loop stop") + { + loopstoptime = keyiter->first; + break; + } + keyiter++; + } + + if(loopstoptime > loopstarttime) + { + Ogre::TransformKeyFrame startkf(0, loopstarttime); + Ogre::TransformKeyFrame endkf(0, loopstoptime); + + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + + mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); + } + } +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); @@ -305,47 +348,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimVelocity = 0.0f; if(mNonAccumRoot) - { - const Ogre::NodeAnimationTrack *track = 0; - - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - track = cur; - } - - if(track && track->getNumKeyFrames() > 1) - { - float loopstarttime = 0.0f; - float loopstoptime = mCurrentAnim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); - while(keyiter != mCurrentKeys->end()) - { - if(keyiter->second == "loop start") - loopstarttime = keyiter->first; - else if(keyiter->second == "loop stop") - { - loopstoptime = keyiter->first; - break; - } - keyiter++; - } - - if(loopstoptime > loopstarttime) - { - Ogre::TransformKeyFrame startkf(0, loopstarttime); - Ogre::TransformKeyFrame endkf(0, loopstoptime); - - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); - - mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); - } - } - } + calcAnimVelocity(); found = true; break; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2f930e9adb..c6e2306707 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -39,6 +39,8 @@ protected: float mAnimVelocity; float mAnimSpeedMult; + void calcAnimVelocity(); + /* Applies the given animation to the given skeleton instance, using the specified time. */ void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); From ecbf1568a1c1a1e37507b5fdd8acdfe7f38ea784 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 10:15:29 -0800 Subject: [PATCH 0415/1483] Fix NPC part attachment --- apps/openmw/mwrender/npcanimation.cpp | 29 ++++++++++++++++----------- apps/openmw/mwrender/npcanimation.hpp | 5 +++-- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 120996a70a..4d8119c72a 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -133,10 +133,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor if(mNpc->mModel.length() > 0) insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - updateParts(); + updateParts(true); } -void NpcAnimation::updateParts() +void NpcAnimation::updateParts(bool forceupdate) { static const struct { int numRemoveParts; // Max: 1 @@ -212,11 +212,21 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + for(size_t i = 0;!forceupdate && i < slotlistsize;i++) + { + MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); + if(this->*slotlist[i].part != iter) + { + forceupdate = true; + break; + } + } + if(!forceupdate) + return; + for(size_t i = 0;i < slotlistsize;i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(this->*slotlist[i].part == iter) - continue; this->*slotlist[i].part = iter; removePartGroup(slotlist[i].slot); @@ -332,12 +342,12 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { - if(mTimeToChange > .2) + if(mTimeToChange <= 0.0f) { - mTimeToChange = 0; + mTimeToChange = 0.2f; updateParts(); } - mTimeToChange += timepassed; + mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); @@ -441,9 +451,4 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector Date: Fri, 22 Feb 2013 11:16:00 -0800 Subject: [PATCH 0416/1483] Fix character preview --- apps/openmw/mwrender/characterpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 24df305566..9f8962d7c3 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -121,8 +121,8 @@ namespace MWRender void InventoryPreview::update(int sizeX, int sizeY) { - mAnimation->runAnimation(0.0f); mAnimation->forceUpdate(); + mAnimation->runAnimation(0.0f); mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); From f17ea109ca653a92da910141640a48ff440cb44f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 04:06:05 +0100 Subject: [PATCH 0417/1483] Fix light positions --- apps/openmw/mwclass/light.cpp | 9 +------- apps/openmw/mwrender/objects.cpp | 39 ++++++++++++++++++++++++++++---- apps/openmw/mwrender/objects.hpp | 4 ++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 235e57d375..094ae5b168 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -36,14 +36,7 @@ namespace MWClass objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); if (!model.empty()) - objects.insertMesh(ptr, "meshes\\" + model); - - const int color = ref->mBase->mData.mColor; - const float r = ((color >> 0) & 0xFF) / 255.0f; - const float g = ((color >> 8) & 0xFF) / 255.0f; - const float b = ((color >> 16) & 0xFF) / 255.0f; - const float radius = float (ref->mBase->mData.mRadius); - objects.insertLight (ptr, r, g, b, radius); + objects.insertMesh(ptr, "meshes\\" + model, true); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bd5f95c240..c51cafc0e1 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -34,6 +34,18 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) for (int i=node->numAttachedObjects()-1; i>=0; --i) { Ogre::MovableObject *object = node->getAttachedObject (i); + + // for entities, destroy any objects attached to bones + if (object->getTypeFlags () == Ogre::SceneManager::ENTITY_TYPE_MASK) + { + Ogre::Entity* ent = static_cast(object); + Ogre::Entity::ChildObjectListIterator children = ent->getAttachedObjectIterator (); + while (children.hasMoreElements()) + { + mRenderer.getScene ()->destroyMovableObject (children.getNext ()); + } + } + node->detachObject (object); mRenderer.getScene()->destroyMovableObject (object); } @@ -87,7 +99,7 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) mIsStatic = static_; } -void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) +void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light) { Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); assert(insert); @@ -204,17 +216,29 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) iter++; } } + + if (light) + { + insertLight(ptr, entities.mSkelBase); + } } -void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius) +void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) { Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle()); assert(insert); - Ogre::Light *light = mRenderer.getScene()->createLight(); - light->setDiffuseColour (r, g, b); MWWorld::LiveCellRef *ref = ptr.get(); + const int color = ref->mBase->mData.mColor; + const float r = ((color >> 0) & 0xFF) / 255.0f; + const float g = ((color >> 8) & 0xFF) / 255.0f; + const float b = ((color >> 16) & 0xFF) / 255.0f; + const float radius = float (ref->mBase->mData.mRadius); + + Ogre::Light *light = mRenderer.getScene()->createLight(); + light->setDiffuseColour (r, g, b); + LightInfo info; info.name = light->getName(); info.radius = radius; @@ -265,7 +289,12 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f light->setAttenuation(r*10, 0, 0, attenuation); } - insert->attachObject(light); + // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node + if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight")) + skelBase->attachObjectToBone ("AttachLight", light); + else + insert->attachObject(light); + mLights.push_back(info); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index b2bdac683f..283c053882 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -73,8 +73,8 @@ public: Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); - void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); - void insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius); + void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase); void enableLights(); void disableLights(); From 5b099393faa2c3cfe4cd4df051f93b452b8a36c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 04:43:51 +0100 Subject: [PATCH 0418/1483] Fix time factor --- apps/openmw/mwrender/refraction.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 67fe9e3405..64234cc572 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -33,7 +33,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.0078, 0.0576, 0.150)); + vp->setBackgroundColour (Ogre::ColourValue(0.180, 0.235, 0.22352)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c4f2d99cb4..5baa8e7ccf 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -349,9 +349,10 @@ void RenderingManager::update (float duration, bool paused) mRendering.update(duration); + Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); + if(paused) { - Ogre::ControllerManager::getSingleton().setTimeFactor(0.f); return; } @@ -520,8 +521,8 @@ void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) configureFog(mCell.mCell->mAmbi.mFogDensity, color); - if (mWater) - mWater->setViewportBackground (Ogre::ColourValue(0.8f, 0.9f, 1.0f)); + //if (mWater) + // mWater->setViewportBackground (Ogre::ColourValue(0.8f, 0.9f, 1.0f)); } void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) From 6f89d453a5213a04eab4c168d495ea71e838a082 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Fri, 22 Feb 2013 21:53:32 -0600 Subject: [PATCH 0419/1483] Operations widget height fix and abort button feature. Successfully tested resizing of Operations QDockWidget for multiple concurrent operations. --- apps/opencs/model/doc/document.cpp | 3 +- apps/opencs/view/doc/operation.cpp | 55 ++++++++++++++++++++++------ apps/opencs/view/doc/operation.hpp | 24 ++++++++++-- apps/opencs/view/doc/operations.cpp | 34 +++++++++++++---- apps/opencs/view/doc/operations.hpp | 6 ++- apps/opencs/view/doc/subview.cpp | 1 - apps/opencs/view/doc/view.cpp | 29 ++++++++++++--- apps/opencs/view/doc/view.hpp | 10 ++++- apps/opencs/view/doc/viewmanager.cpp | 6 ++- 9 files changed, 132 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index da29f6c687..d63aaeccb2 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -249,6 +249,7 @@ void CSMDoc::Document::abortOperation (int type) if (type==State_Saving) { + mSaveCount=0; mSaveTimer.stop(); emit stateChanged (getState(), this); } @@ -297,4 +298,4 @@ CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId& void CSMDoc::Document::progress (int current, int max, int type) { emit progress (current, max, type, 1, this); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index c301195bc7..6977d79535 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -1,8 +1,11 @@ - #include "operation.hpp" #include +#include +#include +#include + #include "../../model/doc/document.hpp" void CSVDoc::Operation::updateLabel (int threads) @@ -28,24 +31,44 @@ void CSVDoc::Operation::updateLabel (int threads) stream << name << " (%p%)"; } - setFormat (stream.str().c_str()); + mProgressBar->setFormat (stream.str().c_str()); } } -CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) +CSVDoc::Operation::Operation (int type, QWidget* parent) : mType (type), mStalling (false) { /// \todo Add a cancel button or a pop up menu with a cancel item + initWidgets(); setBarColor( type); updateLabel(); /// \todo assign different progress bar colours to allow the user to distinguish easily between operation types } +CSVDoc::Operation::~Operation() +{ + delete mLayout; + delete mProgressBar; + delete mAbortButton; +} + +void CSVDoc::Operation::initWidgets() +{ + mProgressBar = new QProgressBar (); + mAbortButton = new QPushButton("Abort"); + mLayout = new QHBoxLayout(); + + mLayout->addWidget (mProgressBar); + mLayout->addWidget (mAbortButton); + + connect (mAbortButton, SIGNAL (clicked()), this, SLOT (abortOperation())); +} + void CSVDoc::Operation::setProgress (int current, int max, int threads) { updateLabel (threads); - setRange (0, max); - setValue (current); + mProgressBar->setRange (0, max); + mProgressBar->setValue (current); } int CSVDoc::Operation::getType() const @@ -64,8 +87,6 @@ void CSVDoc::Operation::setBarColor (int type) "margin: 2px 1px 1p 2px;" "}"; - // "QProgressBar::chunk {background-color: %1;}"; - QString topColor = "#F2F6F8"; QString bottomColor = "#E0EFF9"; QString midTopColor = "#D8E1E7"; @@ -82,7 +103,7 @@ void CSVDoc::Operation::setBarColor (int type) midTopColor = "#F17432"; midBottomColor = "#EA5507"; bottomColor = "#FB955E"; // red gloss #2 - //break; + break; case CSMDoc::State_Searching: @@ -90,7 +111,7 @@ void CSVDoc::Operation::setBarColor (int type) midTopColor = "#ABD3EE"; midBottomColor = "#89C3EB"; bottomColor = "#D5EBFB"; //blue gloss #4 - //break; + break; case CSMDoc::State_Verifying: @@ -98,7 +119,7 @@ void CSVDoc::Operation::setBarColor (int type) midTopColor = "#8EB92A"; midBottomColor = "#72AA00"; bottomColor = "#9ECB2D"; //green gloss - //break; + break; case CSMDoc::State_Compiling: @@ -106,7 +127,7 @@ void CSVDoc::Operation::setBarColor (int type) midTopColor = "#C19E67"; midBottomColor = "#B68D4C"; bottomColor = "#E9D4B3"; //l Brown 3D - //break; + break; default: @@ -116,5 +137,15 @@ void CSVDoc::Operation::setBarColor (int type) midBottomColor = "#B5C6D0"; // gray gloss for undefined ops } - setStyleSheet(style.arg(topColor).arg(midTopColor).arg(midBottomColor).arg(bottomColor)); + mProgressBar->setStyleSheet(style.arg(topColor).arg(midTopColor).arg(midBottomColor).arg(bottomColor)); +} + +QHBoxLayout *CSVDoc::Operation::getLayout() const +{ + return mLayout; +} + +void CSVDoc::Operation::abortOperation() +{ + emit abortOperation (mType); } diff --git a/apps/opencs/view/doc/operation.hpp b/apps/opencs/view/doc/operation.hpp index a5abf73b79..48839fada4 100644 --- a/apps/opencs/view/doc/operation.hpp +++ b/apps/opencs/view/doc/operation.hpp @@ -1,16 +1,23 @@ #ifndef CSV_DOC_OPERATION_H #define CSV_DOC_OPERATION_H -#include +#include + +class QHBoxLayout; +class QPushButton; +class QProgressBar; namespace CSVDoc { - class Operation : public QProgressBar + class Operation : public QObject { Q_OBJECT int mType; bool mStalling; + QProgressBar *mProgressBar; + QPushButton *mAbortButton; + QHBoxLayout *mLayout; // not implemented Operation (const Operation&); @@ -20,15 +27,26 @@ namespace CSVDoc public: - Operation (int type); + Operation (int type, QWidget *parent); + ~Operation(); void setProgress (int current, int max, int threads); int getType() const; + QHBoxLayout *getLayout() const; private: void setBarColor (int type); + void initWidgets(); + + signals: + + void abortOperation (int type); + + private slots: + + void abortOperation(); }; } diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index ba444a119a..71cacbe17e 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -1,7 +1,7 @@ - #include "operations.hpp" #include +#include #include "operation.hpp" @@ -11,12 +11,14 @@ CSVDoc::Operations::Operations() setFeatures (QDockWidget::NoDockWidgetFeatures); - QWidget *widget = new QWidget; - setWidget (widget); - + QWidget *widgetContainer = new QWidget (this); mLayout = new QVBoxLayout; - widget->setLayout (mLayout); + widgetContainer->setLayout (mLayout); + setWidget (widgetContainer); + + setFixedHeight (widgetContainer->height()); + setTitleBarWidget (new QWidget (this)); } void CSVDoc::Operations::setProgress (int current, int max, int type, int threads) @@ -28,11 +30,18 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread return; } - Operation *operation = new Operation (type); + int oldCount = mOperations.size(); + int newCount = oldCount + 1; - mLayout->addWidget (operation); + Operation *operation = new Operation (type, this); + connect (operation, SIGNAL (abortOperation (int)), this, SIGNAL (abortOperation (int))); + + mLayout->addLayout (operation->getLayout()); mOperations.push_back (operation); operation->setProgress (current, max, threads); + + if ( oldCount > 0) + setFixedHeight (height()/oldCount * newCount); } void CSVDoc::Operations::quitOperation (int type) @@ -40,8 +49,17 @@ void CSVDoc::Operations::quitOperation (int type) for (std::vector::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter) if ((*iter)->getType()==type) { + int oldCount = mOperations.size(); + int newCount = oldCount - 1; + + mLayout->removeItem ((*iter)->getLayout()); + delete *iter; mOperations.erase (iter); + + if (oldCount > 1) + setFixedHeight (height() / oldCount * newCount); + break; } -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/operations.hpp b/apps/opencs/view/doc/operations.hpp index b966774502..71c595f66b 100644 --- a/apps/opencs/view/doc/operations.hpp +++ b/apps/opencs/view/doc/operations.hpp @@ -31,7 +31,11 @@ namespace CSVDoc void quitOperation (int type); ///< Calling this function for an operation that is not running is a no-op. + + signals: + + void abortOperation (int type); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index 1c356fa736..affada0124 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -1,4 +1,3 @@ - #include "subview.hpp" CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 4fd03041f8..6aafef4ed0 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -1,4 +1,3 @@ - #include "view.hpp" #include @@ -7,6 +6,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" @@ -117,13 +117,16 @@ void CSVDoc::View::updateActions() mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); } -CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) -: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent) + : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), QMainWindow (viewParent) { setDockOptions (QMainWindow::AllowNestedDocks); resize (300, 300); /// \todo get default size from settings and set reasonable minimal size + mSubViewWindow = new QMainWindow(); + setCentralWidget (mSubViewWindow); + mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); @@ -133,6 +136,8 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to CSVWorld::addSubViewFactories (mSubViewFactory); CSVTools::addSubViewFactories (mSubViewFactory); + + connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); } CSVDoc::View::~View() @@ -171,7 +176,7 @@ void CSVDoc::View::updateDocumentState() for (int i=0; operations[i]!=-1; ++i) if (!(state & operations[i])) - mOperations->quitOperation (operations[i]); + mOperations->quitOperation (operations[i]); QList subViews = findChildren(); @@ -195,7 +200,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) SubView *view = mSubViewFactory.makeSubView (id, *mDocument); - addDockWidget (Qt::TopDockWidgetArea, view); + mSubViewWindow->addDockWidget (Qt::TopDockWidgetArea, view); connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, SLOT (addSubView (const CSMWorld::UniversalId&))); @@ -226,4 +231,16 @@ void CSVDoc::View::addGlobalsSubView() void CSVDoc::View::addGmstsSubView() { addSubView (CSMWorld::UniversalId::Type_Gmsts); -} \ No newline at end of file +} + +void CSVDoc::View::abortOperation (int type) +{ + mDocument->abortOperation (type); + mOperations->quitOperation (type); + updateActions(); +} + +QDockWidget *CSVDoc::View::getOperations() const +{ + return mOperations; +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 6bdd54e6bf..28ab24b744 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -9,6 +9,7 @@ #include "subviewfactory.hpp" class QAction; +class QDockWidget; namespace CSMDoc { @@ -40,6 +41,7 @@ namespace CSVDoc std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; + QMainWindow* mSubViewWindow; // not implemented View (const View&); @@ -65,7 +67,7 @@ namespace CSVDoc public: - View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); + View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent); ///< The ownership of \a document is not transferred to *this. virtual ~View(); @@ -80,6 +82,8 @@ namespace CSVDoc void updateProgress (int current, int max, int type, int threads); + QDockWidget *getOperations() const; + signals: void newDocumentRequest(); @@ -101,7 +105,9 @@ namespace CSVDoc void addGlobalsSubView(); void addGmstsSubView(); + + void abortOperation (int type); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 473049999c..a8faefb970 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -59,7 +59,9 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); } - View *view = new View (*this, document, countViews (document)+1); + QMainWindow *mainWindow = new QMainWindow; + + View *view = new View (*this, document, countViews (document)+1, mainWindow); mViews.push_back (view); @@ -119,4 +121,4 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) (*iter)->updateProgress (current, max, type, threads); -} \ No newline at end of file +} From 01102f9c73b9e28e1fc23928f5123cd2409831f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 05:53:20 +0100 Subject: [PATCH 0420/1483] Don't emit if there wasn't enough movement --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 13 +++++++++++-- apps/openmw/mwrender/ripplesimulation.hpp | 4 +++- apps/openmw/mwrender/water.cpp | 6 ++++++ apps/openmw/mwrender/water.hpp | 2 ++ files/materials/watersim_heightmap.shader | 2 +- 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5baa8e7ccf..c9f7603be6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -376,7 +376,7 @@ void RenderingManager::update (float duration, bool paused) float *fpos = data.getPosition().pos; // only for LocalMap::updatePlayer() - Ogre::Vector3 pos(fpos[0], -fpos[2], -fpos[1]); + Ogre::Vector3 pos(fpos[0], fpos[2], -fpos[1]); Ogre::SceneNode *node = data.getBaseNode(); Ogre::Quaternion orient = diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 249397005b..6c9264b608 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -21,7 +21,8 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) mRippleAreaLength(1000), mImpulseSize(20), mTexelOffset(0,0), - mFirstUpdate(true) + mFirstUpdate(true), + mLastPos(0,0) { Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); @@ -141,8 +142,16 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); } -void RippleSimulation::addImpulse(Ogre::Vector2 position) +void RippleSimulation::addImpulse(Ogre::Vector2 position, float scale, float force) { + // don't emit if there wasn't enough movement + /// \todo this should be done somewhere else, otherwise multiple emitters cannot be supported + if ((position - mLastPos).length () <= 2) + return; + + mLastPos = position; + + /// \todo scale, force mImpulses.push(position); } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index c792a3214e..2f8cae24fd 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -24,7 +24,7 @@ public: void update(float dt, Ogre::Vector2 position); - void addImpulse (Ogre::Vector2 position); + void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); private: Ogre::RenderTexture* mRenderTargets[4]; @@ -34,6 +34,8 @@ private: float mRippleAreaLength; float mImpulseSize; + Ogre::Vector2 mLastPos; + bool mFirstUpdate; Ogre::Camera* mCamera; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f0680f2085..33b6733baa 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -499,4 +499,10 @@ void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& co } } +void Water::addImpulse (Vector2 position, float scale, float force) +{ + if (mSimulation) + mSimulation->addImpulse (position, scale, force); +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 6100b7cfd2..eb7d98f5da 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -146,6 +146,8 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); + void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); + void setViewportBackground(const Ogre::ColourValue& bg); void processChangedSettings(const Settings::CategorySettingVector& settings); diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader index e19270d39e..50d375efe4 100644 --- a/files/materials/watersim_heightmap.shader +++ b/files/materials/watersim_heightmap.shader @@ -1,6 +1,6 @@ #include "core.h" -#define DAMPING 0.92 +#define DAMPING 0.95 #include "watersim_common.h" From 7046e7ae3def07d41d314bbbdb034c45a3e12f64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 09:02:05 +0100 Subject: [PATCH 0421/1483] Water fog fix --- files/materials/water.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/water.shader b/files/materials/water.shader index ac6b81240d..09788d45b1 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -295,7 +295,7 @@ } else { - float fogValue = shSaturate((length(cameraPos.xyz-position.xyz) - fogParams.y) * fogParams.w); + float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); } From 7e816c826bf6c642fee570c099aa29485b0b3ecb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 09:17:12 +0100 Subject: [PATCH 0422/1483] Fix lights without a mesh --- apps/openmw/mwclass/light.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 094ae5b168..9d0fe298b0 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -37,6 +37,8 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); + else + objects.insertLight(ptr, NULL); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const From f841576bba22b7e8b0f2b2ddb61878b64c0c33db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 01:54:46 -0800 Subject: [PATCH 0423/1483] Don't override animations played with playgroup --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6c8d558a4d..7b166ba91a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -218,7 +218,7 @@ Ogre::Vector3 CharacterController::update(float duration) // Apply any sideways movement manually movement.x += vec.x * (speed*duration); } - else + else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } @@ -246,7 +246,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; - mState = CharState_Idle; + mState = CharState_SpecialIdle; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 996687a3e1..2465aea98f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -14,6 +14,7 @@ namespace MWMechanics { enum CharacterState { + CharState_SpecialIdle, CharState_Idle, CharState_Idle2, CharState_Idle3, From c9ca565462b599356e1681bb769218eeda3da411 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:05:09 +0100 Subject: [PATCH 0424/1483] removed a redundant function call --- apps/opencs/view/doc/view.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 6aafef4ed0..286d7a6ed6 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -236,7 +236,6 @@ void CSVDoc::View::addGmstsSubView() void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); - mOperations->quitOperation (type); updateActions(); } From b8f5813609f0c32705d95f83106e2c5005fee19e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 03:34:03 -0800 Subject: [PATCH 0425/1483] Set all animation sources at once --- apps/openmw/mwrender/activatoranimation.cpp | 1 + apps/openmw/mwrender/animation.cpp | 100 +++++++++----------- apps/openmw/mwrender/animation.hpp | 12 ++- apps/openmw/mwrender/creatureanimation.cpp | 11 ++- apps/openmw/mwrender/npcanimation.cpp | 9 +- 5 files changed, 70 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index f951307b68..7bc89b9179 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -51,6 +51,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) ent->setVisibilityFlags(RV_Misc); ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + setAnimationSource(mesh); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 707aedcd93..160641eb0a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,45 +46,64 @@ Animation::~Animation() } -Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) +void Animation::setAnimationSources(const std::vector &names) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(name); - if(skel.isNull()) + + mCurrentAnim = NULL; + mCurrentKeys = NULL; + mAnimVelocity = 0.0f; + mAccumRoot = NULL; + mNonAccumRoot = NULL; + mSkeletonSources.clear(); + + std::vector::const_iterator nameiter = names.begin(); + while(nameiter != names.end()) { - NifOgre::Loader::createSkeleton(name); - skel = skelMgr.getByName(name); + Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); if(skel.isNull()) { - std::cerr<< "Failed to get skeleton source "<touch(); - mSkeletonSources.push_back(skel); + skel->touch(); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); - while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; - - for(int i = 0;i < skel->getNumAnimations();i++) + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) { - Ogre::Animation *anim = skel->getAnimation(i); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); - if(!groupdata.isEmpty()) - mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty() || !Ogre::any_cast(data)) + continue; + + if(!mNonAccumRoot && mEntityList.mSkelBase) + { + mAccumRoot = mInsert; + mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); + } + + mSkeletonSources.push_back(skel); + for(int i = 0;i < skel->getNumAnimations();i++) + { + Ogre::Animation *anim = skel->getAnimation(i); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+anim->getName()); + if(!groupdata.isEmpty()) + mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + } + + break; } - return bone; + nameiter++; } - - return NULL; } void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) @@ -111,31 +130,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); - - Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); - if(!bone) - { - for(std::vector::const_iterator iter(mSkeletonSources.begin()); - !bone && iter != mSkeletonSources.end();iter++) - { - Ogre::Skeleton::BoneIterator boneiter = (*iter)->getBoneIterator(); - while(boneiter.hasMoreElements()) - { - bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(!data.isEmpty() && Ogre::any_cast(data)) - break; - - bone = NULL; - } - } - } - if(bone) - { - mAccumRoot = mInsert; - mNonAccumRoot = skelinst->getBone(bone->getName()); - } } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c6e2306707..130805a506 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -57,9 +57,15 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); - /* Inserts an additional skeleton into the animation source chain. Returns - * the bone representing the non-accum root from the base skeleton. */ - Ogre::Bone *insertSkeletonSource(const std::string &name); + /* Specifies a list of skeleton names to use as animation sources. */ + void setAnimationSources(const std::vector &names); + + /* Specifies a single skeleton name to use as an animation source. */ + void setAnimationSource(const std::string &name) + { + std::vector names(1, name); + setAnimationSources(names); + } void createEntityList(Ogre::SceneNode *node, const std::string &model); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 094281c46b..b85c4dbbda 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -23,10 +23,9 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - if((ref->mBase->mFlags&ESM::Creature::Biped)) - insertSkeletonSource("meshes\\base_anim.nif"); + std::string model = "meshes\\"+ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), "meshes\\"+ref->mBase->mModel); + createEntityList(mPtr.getRefData().getBaseNode(), model); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; @@ -52,6 +51,12 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) } ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + + std::vector names; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + names.push_back("meshes\\base_anim.nif"); + names.push_back(model); + setAnimationSources(names); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4d8119c72a..3f135b7f67 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -125,13 +125,14 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + std::vector skelnames(1, smodel); if(!mNpc->isMale() && !isBeast) - insertSkeletonSource("meshes\\base_anim_female.nif"); + skelnames.push_back("meshes\\base_anim_female.nif"); else if(mBodyPrefix.find("argonian") != std::string::npos) - insertSkeletonSource("meshes\\argonian_swimkna.nif"); - + skelnames.push_back("meshes\\argonian_swimkna.nif"); if(mNpc->mModel.length() > 0) - insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + setAnimationSources(skelnames); updateParts(true); } From 6f5a772d02d886d3777de0b25f45db878f636aad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:35:05 +0100 Subject: [PATCH 0426/1483] fixed another case handling problem --- apps/opencs/model/world/idcollection.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 5a1d21ae4c..9b69dfb889 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -171,7 +171,7 @@ namespace CSMWorld record2.mModified = record; mRecords.push_back (record2); - mIndex.insert (std::make_pair (id, mRecords.size()-1)); + mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), mRecords.size()-1)); } else { @@ -306,7 +306,7 @@ namespace CSMWorld void IdCollection::appendRecord (const RecordBase& record) { mRecords.push_back (dynamic_cast&> (record)); - mIndex.insert (std::make_pair (getId (record), mRecords.size()-1)); + mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (getId (record)), mRecords.size()-1)); } template From 868916a9a22d0dd9f8713b6ea57206d6ee689d52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:51:45 +0100 Subject: [PATCH 0427/1483] added add-on global variables in the same way add-on GMSTs were added --- apps/opencs/model/doc/document.cpp | 32 ++++++++++++++++++++++++++++++ apps/opencs/model/doc/document.hpp | 5 +++++ 2 files changed, 37 insertions(+) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index d63aaeccb2..b361577bec 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -20,6 +20,7 @@ void CSMDoc::Document::load (const std::vector::const_i getData().loadFile (*end2, false); addOptionalGmsts(); + addOptionalGlobals(); } void CSMDoc::Document::addOptionalGmsts() @@ -139,6 +140,26 @@ void CSMDoc::Document::addOptionalGmsts() } } +void CSMDoc::Document::addOptionalGlobals() +{ + static const char *sGlobals[] = + { + "dayspassed", + "pcwerewolf", + "pcyear", + 0 + }; + + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global global; + global.mId = sGlobals[i]; + global.mType = ESM::VT_Int; + global.mValue = 0; + addOptionalGlobal (global); + } +} + void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) { if (getData().getGmsts().searchId (gmst.mId)==-1) @@ -150,6 +171,17 @@ void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) } } +void CSMDoc::Document::addOptionalGlobal (const ESM::Global& global) +{ + if (getData().getGlobals().searchId (global.mId)==-1) + { + CSMWorld::Record record; + record.mBase = global; + record.mState = CSMWorld::RecordBase::State_BaseOnly; + getData().getGlobals().appendRecord (record); + } +} + void CSMDoc::Document::createBase() { static const char *sGlobals[] = diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 413e840d37..a7b198689e 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -20,6 +20,7 @@ class QAbstractItemModel; namespace ESM { struct GameSetting; + struct Global; } namespace CSMDoc @@ -53,8 +54,12 @@ namespace CSMDoc void addOptionalGmsts(); + void addOptionalGlobals(); + void addOptionalGmst (const ESM::GameSetting& gmst); + void addOptionalGlobal (const ESM::Global& global); + public: Document (const std::vector& files, bool new_); From 9659b4a95e1d4bb40560046b288173ec54f07ab2 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 21 Feb 2013 23:56:34 +0400 Subject: [PATCH 0428/1483] update NpcAnimation inventory reference on cell change --- apps/openmw/mwrender/actors.cpp | 4 ++- apps/openmw/mwrender/npcanimation.cpp | 52 +++++++++++++-------------- apps/openmw/mwrender/npcanimation.hpp | 8 ++++- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 92f5cbe28d..e886f3a093 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -163,7 +163,9 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { /// \note Update key (Ptr's are compared only with refdata so mCell /// on key is outdated), maybe redundant - Animation *anim = iter->second; + NpcAnimation *anim = static_cast(iter->second); + anim->updateParts(MWWorld::Class::get(ptr).getInventoryStore(ptr)); + mAllActors.erase(iter); mAllActors[ptr] = anim; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d33bdda91d..6f6c9e740f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -48,21 +48,21 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(), mStateID(-1), - mInv(inv), + mInv(&inv), mTimeToChange(0), mVisibilityFlags(visibilityFlags), - mRobe(mInv.end()), - mHelmet(mInv.end()), - mShirt(mInv.end()), - mCuirass(mInv.end()), - mGreaves(mInv.end()), - mPauldronL(mInv.end()), - mPauldronR(mInv.end()), - mBoots(mInv.end()), - mPants(mInv.end()), - mGloveL(mInv.end()), - mGloveR(mInv.end()), - mSkirtIter(mInv.end()) + mRobe(mInv->end()), + mHelmet(mInv->end()), + mShirt(mInv->end()), + mCuirass(mInv->end()), + mGreaves(mInv->end()), + mPauldronL(mInv->end()), + mPauldronR(mInv->end()), + mBoots(mInv->end()), + mPants(mInv->end()), + mGloveL(mInv->end()), + mGloveR(mInv->end()), + mSkirtIter(mInv->end()) { mNpc = ptr.get()->mBase; @@ -160,7 +160,7 @@ void NpcAnimation::updateParts() }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { - MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); if(*slotlist[i].iter != iter) { *slotlist[i].iter = iter; @@ -171,7 +171,7 @@ void NpcAnimation::updateParts() if(apparelChanged) { - if(mRobe != mInv.end()) + if(mRobe != mInv->end()) { MWWorld::Ptr ptr = *mRobe; @@ -191,7 +191,7 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); } - if(mSkirtIter != mInv.end()) + if(mSkirtIter != mInv->end()) { MWWorld::Ptr ptr = *mSkirtIter; @@ -203,39 +203,39 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); } - if(mHelmet != mInv.end()) + if(mHelmet != mInv->end()) { removeIndividualPart(ESM::PRT_Hair); const ESM::Armor *armor = (mHelmet->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); } - if(mCuirass != mInv.end()) + if(mCuirass != mInv->end()) { const ESM::Armor *armor = (mCuirass->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); } - if(mGreaves != mInv.end()) + if(mGreaves != mInv->end()) { const ESM::Armor *armor = (mGreaves->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); } - if(mPauldronL != mInv.end()) + if(mPauldronL != mInv->end()) { const ESM::Armor *armor = (mPauldronL->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); } - if(mPauldronR != mInv.end()) + if(mPauldronR != mInv->end()) { const ESM::Armor *armor = (mPauldronR->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); } - if(mBoots != mInv.end()) + if(mBoots != mInv->end()) { if(mBoots->getTypeName() == typeid(ESM::Clothing).name()) { @@ -250,7 +250,7 @@ void NpcAnimation::updateParts() addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); } } - if(mGloveL != mInv.end()) + if(mGloveL != mInv->end()) { if(mGloveL->getTypeName() == typeid(ESM::Clothing).name()) { @@ -265,7 +265,7 @@ void NpcAnimation::updateParts() addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); } } - if(mGloveR != mInv.end()) + if(mGloveR != mInv->end()) { if(mGloveR->getTypeName() == typeid(ESM::Clothing).name()) { @@ -282,13 +282,13 @@ void NpcAnimation::updateParts() } - if(mShirt != mInv.end()) + if(mShirt != mInv->end()) { const ESM::Clothing *clothes = (mShirt->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); } - if(mPants != mInv.end()) + if(mPants != mInv->end()) { const ESM::Clothing *clothes = (mPants->get())->mBase; std::vector parts = clothes->mParts.mParts; diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ca76dcc222..fd1a96aa3e 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -17,7 +17,7 @@ namespace MWRender{ class NpcAnimation: public Animation{ private: - MWWorld::InventoryStore& mInv; + MWWorld::InventoryStore *mInv; int mStateID; int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty @@ -78,7 +78,13 @@ public: virtual ~NpcAnimation(); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); virtual void runAnimation(float timepassed); + void updateParts(); + void updateParts(MWWorld::InventoryStore &inventory) { + mInv = &inventory; + updateParts(); + } + void removeEntities(NifOgre::EntityList &entities); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); From d983ed5c7819046ad4c0166c61f6cc47575196f7 Mon Sep 17 00:00:00 2001 From: greye Date: Fri, 22 Feb 2013 11:14:14 +0400 Subject: [PATCH 0429/1483] fix invalid SceneNode pointer on cell change --- apps/openmw/mwworld/worldimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ca054e776b..12193de408 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -746,7 +746,11 @@ namespace MWWorld copyObjectToCell(ptr, newCell, pos); else if (!mWorldScene->isCellActive(newCell)) { - MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + MWWorld::Class::get(ptr) + .copyToCell(ptr, newCell) + .getRefData() + .setBaseNode(0); + mWorldScene->removeObjectFromScene(ptr); mLocalScripts.remove(ptr); removeContainerScripts (ptr); From ac7095537f9626f62ee9437b241371356b92526e Mon Sep 17 00:00:00 2001 From: greye Date: Sat, 23 Feb 2013 16:50:37 +0400 Subject: [PATCH 0430/1483] remove insertMesh() call on object cell change --- apps/openmw/mwrender/objects.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index ee36126f8d..16ac163ecc 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -514,9 +514,5 @@ void Objects::updateObjectCell(const MWWorld::Ptr &ptr) node = mCellSceneNodes[newCell]; } node->addChild(ptr.getRefData().getBaseNode()); - - /// \note Still unaware how to move aabb and static w/o full rebuild, - /// moving static objects may cause problems - insertMesh(ptr, MWWorld::Class::get(ptr).getModel(ptr)); } From a3adcf752d9796279f175d7fbd01080ac53b227f Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Fri, 22 Feb 2013 21:33:23 +0400 Subject: [PATCH 0431/1483] TradeWindow: fixed coding style Mentioned here: https://github.com/zinnschlag/openmw/pull/554 --- apps/openmw/mwgui/tradewindow.cpp | 12 ++++++------ apps/openmw/mwgui/tradewindow.hpp | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2cc8ff4443..290310760e 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -19,11 +19,11 @@ #include "inventorywindow.hpp" -static const float BALANCE_CHANGE_INITIAL_PAUSE = 0.5; // in seconds -static const float BALANCE_CHANGE_INTERVAL = 0.1; // in seconds - namespace MWGui { + const float TradeWindow::sBalanceChangeInitialPause = 0.5; + const float TradeWindow::sBalanceChangeInterval = 0.1; + TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_trade_window.layout", parWindowManager) , ContainerBase(NULL) // no drag&drop @@ -157,7 +157,7 @@ namespace MWGui mBalanceChangePause -= frameDuration; if (mBalanceChangePause < 0.0) { - mBalanceChangePause += BALANCE_CHANGE_INTERVAL; + mBalanceChangePause += sBalanceChangeInterval; if (mBalanceButtonsState == BBS_Increase) onIncreaseButtonTriggered(); else if (mBalanceButtonsState == BBS_Decrease) @@ -296,14 +296,14 @@ namespace MWGui void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { mBalanceButtonsState = BBS_Increase; - mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + mBalanceChangePause = sBalanceChangeInitialPause; onIncreaseButtonTriggered(); } void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { mBalanceButtonsState = BBS_Decrease; - mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + mBalanceChangePause = sBalanceChangeInitialPause; onDecreaseButtonTriggered(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 20d9b60691..c1d31917ba 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -37,6 +37,9 @@ namespace MWGui void onFrame(float frameDuration); protected: + static const float sBalanceChangeInitialPause; // in seconds + static const float sBalanceChangeInterval; // in seconds + MyGUI::Button* mFilterAll; MyGUI::Button* mFilterWeapon; MyGUI::Button* mFilterApparel; From e6da9dfae533065a4c258007160b3269c3407a09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 05:15:10 -0800 Subject: [PATCH 0432/1483] Specify the animation key to stop playing at --- apps/openmw/mwmechanics/character.cpp | 10 +++--- apps/openmw/mwrender/animation.cpp | 43 ++++++++++++++--------- apps/openmw/mwrender/animation.hpp | 11 +++--- apps/openmw/mwrender/characterpreview.cpp | 2 +- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7b166ba91a..5598e0e56f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -113,7 +113,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop", loop); + mAnimation->play(mCurrentGroup, "stop", "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) @@ -152,7 +152,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", false); } else if(mAnimQueue.size() > 0) { @@ -160,7 +160,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", false); + mAnimation->play(mCurrentGroup, "start", "stop", false); } } return; @@ -247,7 +247,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", false); } else if(mode == 0) { @@ -283,7 +283,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 160641eb0a..1dd46365bc 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentKeys(NULL) , mCurrentAnim(NULL) , mCurrentTime(0.0f) + , mStopTime(0.0f) , mPlaying(false) , mLooping(false) , mAnimVelocity(0.0f) @@ -293,12 +294,12 @@ Ogre::Vector3 Animation::updatePosition(float time) return posdiff; } -void Animation::reset(const std::string &marker) +void Animation::reset(const std::string &start, const std::string &stop) { mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) - mNextKey++; + while(mNextKey != mCurrentKeys->end() && mNextKey->second != start) + mNextKey++; if(mNextKey != mCurrentKeys->end()) mCurrentTime = mNextKey->first; else @@ -307,6 +308,17 @@ void Animation::reset(const std::string &marker) mCurrentTime = 0.0f; } + if(stop.length() > 0) + { + NifOgre::TextKeyMap::const_iterator stopKey = mNextKey; + while(stopKey != mCurrentKeys->end() && stopKey->second != stop) + stopKey++; + if(stopKey != mCurrentKeys->end()) + mStopTime = stopKey->first; + else + mStopTime = mCurrentAnim->getLength(); + } + if(mNonAccumRoot) { const Ogre::NodeAnimationTrack *track = 0; @@ -328,7 +340,7 @@ void Animation::reset(const std::string &marker) } -void Animation::play(const std::string &groupname, const std::string &start, bool loop) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { bool found = false; @@ -351,9 +363,9 @@ void Animation::play(const std::string &groupname, const std::string &start, boo if(!found) throw std::runtime_error("Failed to find animation "+groupname); - reset(start); + reset(start, stop); + setLooping(loop); mPlaying = true; - mLooping = loop; } catch(std::exception &e) { std::cerr<< e.what() <end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (mLooping || mCurrentAnim->getLength() >= targetTime); + mPlaying = (mLooping || mStopTime > targetTime); break; } @@ -380,6 +392,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) mNextKey++; movement += updatePosition(time); + mPlaying = (mLooping || mStopTime > time); + timepassed = targetTime - time; if(evt == "start" || evt == "loop start") @@ -391,7 +405,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - reset("loop start"); + reset("loop start", ""); if(mCurrentTime >= time) break; } @@ -401,17 +415,12 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - reset("loop start"); + reset("loop start", ""); if(mCurrentTime >= time) break; + continue; } - else - { - mPlaying = false; - if(mController) - mController->markerEvent(time, evt); - } - continue; + // fall-through } if(mController) mController->markerEvent(time, evt); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 130805a506..47bc8c3900 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,6 +33,7 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; float mCurrentTime; + float mStopTime; bool mPlaying; bool mLooping; @@ -53,9 +54,11 @@ protected: * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Resets the animation to the time of the specified marker, without moving - * anything. If the marker is not found, it resets to the beginning. */ - void reset(const std::string &marker); + /* Resets the animation to the time of the specified start marker, without + * moving anything, and set the end time to the specified stop marker. If + * the marker is not found, it resets to the beginning or end respectively. + */ + void reset(const std::string &start, const std::string &stop); /* Specifies a list of skeleton names to use as animation sources. */ void setAnimationSources(const std::vector &names); @@ -86,7 +89,7 @@ public: void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, bool loop); + void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 9f8962d7c3..36cac2155d 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -145,7 +145,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->play("inventoryhandtohand", "start", false); + mAnimation->play("inventoryhandtohand", "start", "stop", false); } // -------------------------------------------------------------------------------------------------- From 3472a6f180e81ab510026b4b96760adf4d145181 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 14:40:56 +0100 Subject: [PATCH 0433/1483] workaround for infinite recursion during local variable access --- apps/openmw/mwscript/scriptmanagerimp.cpp | 42 +++++++++++++++-------- apps/openmw/mwscript/scriptmanagerimp.hpp | 1 + 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 1f338edbd3..e8489e3cd0 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -140,25 +140,37 @@ namespace MWScript Compiler::Locals& ScriptManager::getLocals (const std::string& name) { - ScriptCollection::iterator iter = mScripts.find (name); - - if (iter==mScripts.end()) { - if (!compile (name)) - { - /// \todo Handle case of cyclic member variable access. Currently this could look up - /// the whole application in an endless recursion. + ScriptCollection::iterator iter = mScripts.find (name); - // failed -> ignore script from now on. - std::vector empty; - mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); - throw std::runtime_error ("failed to compile script " + name); - } - - iter = mScripts.find (name); + if (iter!=mScripts.end()) + return iter->second.second; } - return iter->second.second; + { + std::map::iterator iter = mOtherLocals.find (name); + + if (iter!=mOtherLocals.end()) + return iter->second; + } + + Compiler::Locals locals; + + if (const ESM::Script *script = mStore.get().find (name)) + { + int index = 0; + + for (int i=0; imData.mNumShorts; ++i) + locals.declare ('s', script->mVarNames[index++]); + + for (int i=0; imData.mNumLongs; ++i) + locals.declare ('l', script->mVarNames[index++]); + + for (int i=0; imData.mNumFloats; ++i) + locals.declare ('f', script->mVarNames[index++]); + } + + throw std::logic_error ("script " + name + " does not exist"); } GlobalScripts& ScriptManager::getGlobalScripts() diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index c4a016eb79..1a856e0c58 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -47,6 +47,7 @@ namespace MWScript ScriptCollection mScripts; GlobalScripts mGlobalScripts; + std::map mOtherLocals; public: From 89dace3cc3bea36c7fec02b7b5bba629ab5e8e89 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 23 Feb 2013 09:07:13 -0600 Subject: [PATCH 0434/1483] Fix for operations widget - hides when no operations are running. --- apps/opencs/view/doc/operations.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index 71cacbe17e..ce001afaa9 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -16,7 +16,7 @@ CSVDoc::Operations::Operations() widgetContainer->setLayout (mLayout); setWidget (widgetContainer); - + setVisible (false); setFixedHeight (widgetContainer->height()); setTitleBarWidget (new QWidget (this)); } @@ -42,6 +42,8 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread if ( oldCount > 0) setFixedHeight (height()/oldCount * newCount); + + setVisible (true); } void CSVDoc::Operations::quitOperation (int type) @@ -59,6 +61,8 @@ void CSVDoc::Operations::quitOperation (int type) if (oldCount > 1) setFixedHeight (height() / oldCount * newCount); + else + setVisible (false); break; } From 0d0e75fe0b74c265e6ae31a5dccfa2e240fc196e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 07:36:11 -0800 Subject: [PATCH 0435/1483] Don't set animation sources for models that don't have a skeleton --- apps/openmw/mwrender/animation.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1dd46365bc..29652ca6a9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -49,6 +49,9 @@ Animation::~Animation() void Animation::setAnimationSources(const std::vector &names) { + if(!mEntityList.mSkelBase) + return; + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); mCurrentAnim = NULL; @@ -59,7 +62,7 @@ void Animation::setAnimationSources(const std::vector &names) mSkeletonSources.clear(); std::vector::const_iterator nameiter = names.begin(); - while(nameiter != names.end()) + for(nameiter = names.begin();nameiter != names.end();nameiter++) { Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); if(skel.isNull()) @@ -69,7 +72,6 @@ void Animation::setAnimationSources(const std::vector &names) if(skel.isNull()) { std::cerr<< "Failed to get skeleton source "<<*nameiter < &names) if(data.isEmpty() || !Ogre::any_cast(data)) continue; - if(!mNonAccumRoot && mEntityList.mSkelBase) + if(!mNonAccumRoot) { mAccumRoot = mInsert; mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); @@ -102,8 +104,6 @@ void Animation::setAnimationSources(const std::vector &names) break; } - - nameiter++; } } From a2eaec787802d80f62917e13037b75e696d04213 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 08:03:52 -0800 Subject: [PATCH 0436/1483] Avoiding holding the InventoryStore in the NpcAnimation class --- apps/openmw/mwrender/actors.cpp | 6 +---- apps/openmw/mwrender/npcanimation.cpp | 34 ++++++++++++++------------- apps/openmw/mwrender/npcanimation.hpp | 12 ++++------ 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 3f31459005..d356d922e5 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -167,11 +167,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) PtrAnimationMap::iterator iter = mAllActors.find(ptr); if(iter != mAllActors.end()) { - /// \note Update key (Ptr's are compared only with refdata so mCell - /// on key is outdated), maybe redundant - NpcAnimation *anim = static_cast(iter->second); - anim->updateParts(MWWorld::Class::get(ptr).getInventoryStore(ptr)); - + Animation *anim = iter->second; mAllActors.erase(iter); mAllActors[ptr] = anim; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index dcaee55f99..809e3f6d29 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -5,6 +5,8 @@ #include #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -54,22 +56,21 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(ptr), - mInv(&inv), mStateID(-1), mTimeToChange(0), mVisibilityFlags(visibilityFlags), - mRobe(mInv->end()), - mHelmet(mInv->end()), - mShirt(mInv->end()), - mCuirass(mInv->end()), - mGreaves(mInv->end()), - mPauldronL(mInv->end()), - mPauldronR(mInv->end()), - mBoots(mInv->end()), - mPants(mInv->end()), - mGloveL(mInv->end()), - mGloveR(mInv->end()), - mSkirtIter(mInv->end()) + mRobe(inv.end()), + mHelmet(inv.end()), + mShirt(inv.end()), + mCuirass(inv.end()), + mGreaves(inv.end()), + mPauldronL(inv.end()), + mPauldronR(inv.end()), + mBoots(inv.end()), + mPants(inv.end()), + mGloveL(inv.end()), + mGloveR(inv.end()), + mSkirtIter(inv.end()) { mNpc = mPtr.get()->mBase; @@ -213,9 +214,10 @@ void NpcAnimation::updateParts(bool forceupdate) }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for(size_t i = 0;!forceupdate && i < slotlistsize;i++) { - MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); if(this->*slotlist[i].part != iter) { forceupdate = true; @@ -227,12 +229,12 @@ void NpcAnimation::updateParts(bool forceupdate) for(size_t i = 0;i < slotlistsize;i++) { - MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); this->*slotlist[i].part = iter; removePartGroup(slotlist[i].slot); - if(this->*slotlist[i].part == mInv->end()) + if(this->*slotlist[i].part == inv.end()) continue; for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index c5d5b74619..aed4868bdd 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -3,7 +3,6 @@ #include "animation.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/containerstore.hpp" namespace ESM @@ -11,6 +10,11 @@ namespace ESM struct NPC; } +namespace MWWorld +{ + class InventoryStore; +} + namespace MWRender { @@ -26,7 +30,6 @@ private: static const size_t sPartListSize = 27; static const PartInfo sPartList[sPartListSize]; - MWWorld::InventoryStore *mInv; int mStateID; // Bounded Parts @@ -75,11 +78,6 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); - void updateParts(MWWorld::InventoryStore &inventory) - { - mInv = &inventory; - updateParts(true); - } void forceUpdate() { updateParts(true); } }; From 61fc8ad6e4bed33473c891b3268d91bc2168a56e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 18:56:07 +0100 Subject: [PATCH 0437/1483] updated credits files --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 5c966d86b2..8b396aad0a 100644 --- a/credits.txt +++ b/credits.txt @@ -40,6 +40,7 @@ Nikolay Kasyanov (corristo) Pieter van der Kloet (pvdk) Roman Melnik (Kromgart) Sebastian Wick (swick) +Sergey Shambir Sylvain T. (Garvek) Tom Mason (wheybags) From d208422ca76da90b9a5a0fa12b47722122948b8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 10:12:36 -0800 Subject: [PATCH 0438/1483] Add a method to update an Animation's Ptr object --- apps/openmw/mwrender/actors.cpp | 1 + apps/openmw/mwrender/animation.cpp | 5 +++++ apps/openmw/mwrender/animation.hpp | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index d356d922e5..485e3a7adc 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -169,6 +169,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { Animation *anim = iter->second; mAllActors.erase(iter); + anim->updatePtr(ptr); mAllActors[ptr] = anim; } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 29652ca6a9..39323edac2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,6 +169,11 @@ void Animation::setLooping(bool loop) mLooping = loop; } +void Animation::updatePtr(const MWWorld::Ptr &ptr) +{ + mPtr = ptr; +} + void Animation::calcAnimVelocity() { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 47bc8c3900..b8323cb895 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -49,7 +49,6 @@ protected: * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); - /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); @@ -78,6 +77,8 @@ public: void setController(MWMechanics::CharacterController *controller); + void updatePtr(const MWWorld::Ptr &ptr); + bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just From 44b1c66c4b1a976024ac1f664793d80737cd27ce Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 14 Feb 2013 21:38:27 -0800 Subject: [PATCH 0439/1483] fixed various warnings about converting size_t to int --- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/store.hpp | 16 ++++++++-------- components/esm/esmwriter.cpp | 10 +++++----- components/esm/esmwriter.hpp | 8 ++++---- components/to_utf8/to_utf8.cpp | 4 ++-- components/to_utf8/to_utf8.hpp | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b917a89168..254e05e7f6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -25,7 +25,7 @@ namespace const MWWorld::Class& class_ = MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); - int numRefs = cellRefList.mList.size(); + size_t numRefs = cellRefList.mList.size(); int current = 0; for (typename T::List::iterator it = cellRefList.mList.begin(); it != cellRefList.mList.end(); it++) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index cb18873cc4..c05e372838 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -17,7 +17,7 @@ namespace MWWorld virtual void setUp() {} virtual void listIdentifier(std::vector &list) const {} - virtual int getSize() const = 0; + virtual size_t getSize() const = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; virtual bool eraseStatic(const std::string &id) {return false;} @@ -158,7 +158,7 @@ namespace MWWorld return mShared.end(); } - int getSize() const { + size_t getSize() const { return mShared.size(); } @@ -269,11 +269,11 @@ namespace MWWorld return ptr; } - int getSize() const { + size_t getSize() const { return mStatic.size(); } - int getSize(size_t plugin) const { + size_t getSize(size_t plugin) const { assert(plugin < mStatic.size()); return mStatic[plugin].size(); } @@ -338,7 +338,7 @@ namespace MWWorld } - int getSize() const { + size_t getSize() const { return mStatic.size(); } @@ -567,7 +567,7 @@ namespace MWWorld return 0; } - int getSize() const { + size_t getSize() const { return mSharedInt.size() + mSharedExt.size(); } @@ -701,7 +701,7 @@ namespace MWWorld mStatic.back().load(esm); } - int getSize() const { + size_t getSize() const { return mStatic.size(); } @@ -930,7 +930,7 @@ namespace MWWorld } } - int getSize() const { + size_t getSize() const { return mStatic.size(); } diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index e2f878a257..b9dd5b57b6 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -136,15 +136,15 @@ void ESMWriter::writeHNString(const std::string& name, const std::string& data) endRecord(name); } -void ESMWriter::writeHNString(const std::string& name, const std::string& data, int size) +void ESMWriter::writeHNString(const std::string& name, const std::string& data, size_t size) { - assert(static_cast (data.size()) <= size); + assert(data.size() <= size); startSubRecord(name); writeHString(data); - if (static_cast (data.size()) < size) + if (data.size() < size) { - for (int i = data.size(); i < size; ++i) + for (size_t i = data.size(); i < size; ++i) write("\0",1); } @@ -177,7 +177,7 @@ void ESMWriter::writeName(const std::string& name) write(name.c_str(), name.size()); } -void ESMWriter::write(const char* data, int size) +void ESMWriter::write(const char* data, size_t size) { if (count && !m_records.empty()) { diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index b557a29ad8..94e173b4ce 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -16,7 +16,7 @@ class ESMWriter { std::string name; std::streampos position; - int size; + size_t size; }; public: @@ -35,7 +35,7 @@ public: void close(); void writeHNString(const std::string& name, const std::string& data); - void writeHNString(const std::string& name, const std::string& data, int size); + void writeHNString(const std::string& name, const std::string& data, size_t size); void writeHNCString(const std::string& name, const std::string& data) { startSubRecord(name); @@ -76,7 +76,7 @@ public: } template - void writeT(const T& data, int size) + void writeT(const T& data, size_t size) { write((char*)&data, size); } @@ -87,7 +87,7 @@ public: void writeHString(const std::string& data); void writeHCString(const std::string& data); void writeName(const std::string& data); - void write(const char* data, int size); + void write(const char* data, size_t size); private: std::list m_masters; diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index e2a1b1220f..1de15d79c4 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -70,7 +70,7 @@ Utf8Encoder::Utf8Encoder(const FromType sourceEncoding): } } -std::string Utf8Encoder::getUtf8(const char* input, int size) +std::string Utf8Encoder::getUtf8(const char* input, size_t size) { // Double check that the input string stops at some point (it might // contain zero terminators before this, inside its own data, which @@ -111,7 +111,7 @@ std::string Utf8Encoder::getUtf8(const char* input, int size) return std::string(&mOutput[0], outlen); } -std::string Utf8Encoder::getLegacyEnc(const char *input, int size) +std::string Utf8Encoder::getLegacyEnc(const char *input, size_t size) { // Double check that the input string stops at some point (it might // contain zero terminators before this, inside its own data, which diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index d975b3e4d0..839aa36aa3 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -27,13 +27,13 @@ namespace ToUTF8 Utf8Encoder(FromType sourceEncoding); // Convert to UTF8 from the previously given code page. - std::string getUtf8(const char *input, int size); + std::string getUtf8(const char *input, size_t size); inline std::string getUtf8(const std::string &str) { return getUtf8(str.c_str(), str.size()); } - std::string getLegacyEnc(const char *input, int size); + std::string getLegacyEnc(const char *input, size_t size); inline std::string getLegacyEnc(const std::string &str) { return getLegacyEnc(str.c_str(), str.size()); From 1af4e11414c94e4691acefb2fe987790570ae8b4 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 23 Feb 2013 10:24:18 -0800 Subject: [PATCH 0440/1483] apply MSVC warning settings to shiny projects --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ef85e34dd..95d54fed1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -529,6 +529,8 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) + set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${WARNINGS}) + set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) if (BUILD_LAUNCHER) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) From a95431c387258d0f3862a9e8a5345336602a4cb2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 20:20:40 +0100 Subject: [PATCH 0441/1483] fix --- apps/openmw/mwscript/scriptmanagerimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index e8489e3cd0..fed5877c4b 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -168,6 +168,11 @@ namespace MWScript for (int i=0; imData.mNumFloats; ++i) locals.declare ('f', script->mVarNames[index++]); + + std::map::iterator iter = + mOtherLocals.insert (std::make_pair (name, locals)).first; + + return iter->second; } throw std::logic_error ("script " + name + " does not exist"); From df8889dcc4eb772a8689252e940ba1275d8fd2fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 13:15:37 -0800 Subject: [PATCH 0442/1483] Limit maximum frame time to 200ms This effectively slows game time when it drops below 5 fps. Something like this is desirable when dealing with time-based animations, which can jump forward after a lengthy cell transition. --- apps/openmw/engine.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7dc18c6e87..6f59349fd5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -67,14 +67,15 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { - mEnvironment.setFrameDuration (evt.timeSinceLastFrame); + float frametime = std::min(evt.timeSinceLastFrame, 0.2f); + mEnvironment.setFrameDuration(frametime); // update input - MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame, false); + MWBase::Environment::get().getInputManager()->update(frametime, false); // sound if (mUseSound) - MWBase::Environment::get().getSoundManager()->update (evt.timeSinceLastFrame); + MWBase::Environment::get().getSoundManager()->update(frametime); // global scripts MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); @@ -88,19 +89,19 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // passing of time if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->advanceTime ( - mEnvironment.getFrameDuration()*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + MWBase::Environment::get().getWorld()->advanceTime( + frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); if (changed) // keep change flag for another frame, if cell changed happend in local script MWBase::Environment::get().getWorld()->markCellAsUnchanged(); // update actors - MWBase::Environment::get().getMechanicsManager()->update(mEnvironment.getFrameDuration(), + MWBase::Environment::get().getMechanicsManager()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); // update world - MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode()); + MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); @@ -108,7 +109,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); - MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); + MWBase::Environment::get().getWindowManager()->onFrame(frametime); } catch (const std::exception& e) { From d77d035d3a32fe7eefd567068572c805a17a5e97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 14:15:11 -0800 Subject: [PATCH 0443/1483] Handle the "sound" events in runAnimation --- apps/openmw/mwmechanics/character.cpp | 14 -------------- apps/openmw/mwrender/animation.cpp | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5598e0e56f..37477932a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -24,7 +24,6 @@ #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -134,19 +133,6 @@ CharacterController::~CharacterController() void CharacterController::markerEvent(float time, const std::string &evt) { - if(evt.compare(0, 7, "sound: ") == 0) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); - return; - } - if(evt.compare(0, 10, "soundgen: ") == 0) - { - // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds - // to this actor type - return; - } - if(evt == "stop") { if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 39323edac2..f453e6a740 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,6 +8,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/character.hpp" @@ -406,6 +407,20 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) /* Do nothing */ continue; } + + if(evt.compare(0, 7, "sound: ") == 0) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + continue; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + continue; + } + if(evt == "loop stop") { if(mLooping) From 150d4a7a7292bd1d6cc86bcd4d3177635111e146 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sat, 23 Feb 2013 23:18:42 +0100 Subject: [PATCH 0444/1483] Added support for multiple ini files --- apps/launcher/maindialog.cpp | 23 +++++++++++++++++++---- apps/launcher/settings/gamesettings.cpp | 18 ++---------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 77526677b8..c03a31fd59 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -180,7 +180,7 @@ bool MainDialog::showFirstRunDialog() if (msgBox.clickedButton() == importerButton) { - QString iniPath; + QStringList iniPaths; foreach (const QString &path, mGameSettings.getDataDirs()) { QDir dir(path); @@ -190,10 +190,10 @@ bool MainDialog::showFirstRunDialog() continue; // Cannot move from Data Files if (dir.exists(QString("Morrowind.ini"))) - iniPath = dir.absoluteFilePath(QString("Morrowind.ini")); + iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini"))); } - if (iniPath.isEmpty()) { + if (iniPaths.isEmpty()) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Error reading Morrowind configuration file")); msgBox.setIcon(QMessageBox::Warning); @@ -205,6 +205,21 @@ bool MainDialog::showFirstRunDialog() return false; } + if (iniPaths.count() > 1) { + // Multiple Morrowind.ini files found + bool ok; + QString path = QInputDialog::getItem(this, tr("Multiple configurations found"), + tr("
There are multiple Morrowind.ini files found.

\ + Please select the one you wish to import from:"), iniPaths, 0, false, &ok); + if (ok && !path.isEmpty()) { + iniPaths.clear(); + iniPaths.append(path); + } else { + // Cancel was clicked TODO: should we abort here? + return false; + } + } + // Create the file if it doesn't already exist, else the importer will fail QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg"); QFile file(path); @@ -232,7 +247,7 @@ bool MainDialog::showFirstRunDialog() if (msgBox.isChecked()) arguments.append(QString("-g")); - arguments.append(iniPath); + arguments.append(iniPaths.first()); arguments.append(path); if (!startProgram(QString("mwiniimport"), arguments, false)) diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 20ccebc97c..6b46a5160b 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -21,11 +21,10 @@ GameSettings::~GameSettings() void GameSettings::validatePaths() { - if (mSettings.isEmpty()) - return; + if (mSettings.isEmpty() || !mDataDirs.isEmpty()) + return; // Don't re-validate paths if they are already parsed QStringList paths = mSettings.values(QString("data")); - qDebug() << "paths " << paths; Files::PathContainer dataDirs; foreach (const QString &path, paths) { @@ -89,19 +88,6 @@ bool GameSettings::readFile(QTextStream &stream) QString key = keyRe.cap(1).simplified(); QString value = keyRe.cap(2).simplified(); -// // There can be multiple keys -// if (key == QLatin1String("data") || -// key == QLatin1String("master") || -// key == QLatin1String("plugin")) -// { -// // Remove keys from previous config and overwrite them -// mSettings.remove(key); -// QStringList values = cache.values(key); -// if (!values.contains(value)) // Do not insert duplicate values -// cache.insertMulti(key, value); -// } else { -// cache.insert(key, value); -// } mSettings.remove(key); QStringList values = cache.values(key); From 8e59ea494171740fb7b80d0e8f87ee7a24536f77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 14:39:01 -0800 Subject: [PATCH 0445/1483] Use a separate method to handle animation events --- apps/openmw/mwrender/animation.cpp | 92 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f453e6a740..394e25b504 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -346,6 +346,54 @@ void Animation::reset(const std::string &start, const std::string &stop) } +bool Animation::handleEvent(float time, const std::string &evt) +{ + if(evt == "start" || evt == "loop start") + { + /* Do nothing */ + return true; + } + + if(evt.compare(0, 7, "sound: ") == 0) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + return true; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + return true; + } + + if(evt == "loop stop") + { + if(mLooping) + { + reset("loop start", ""); + if(mCurrentTime >= time) + return false; + } + return true; + } + if(evt == "stop") + { + if(mLooping) + { + reset("loop start", ""); + if(mCurrentTime >= time) + return false; + return true; + } + // fall-through + } + if(mController) + mController->markerEvent(time, evt); + return true; +} + + void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { @@ -402,48 +450,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) timepassed = targetTime - time; - if(evt == "start" || evt == "loop start") - { - /* Do nothing */ - continue; - } - - if(evt.compare(0, 7, "sound: ") == 0) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); - continue; - } - if(evt.compare(0, 10, "soundgen: ") == 0) - { - // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds - // to this actor type - continue; - } - - if(evt == "loop stop") - { - if(mLooping) - { - reset("loop start", ""); - if(mCurrentTime >= time) - break; - } - continue; - } - if(evt == "stop") - { - if(mLooping) - { - reset("loop start", ""); - if(mCurrentTime >= time) - break; - continue; - } - // fall-through - } - if(mController) - mController->markerEvent(time, evt); + if(!handleEvent(time, evt)) + break; } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b8323cb895..810ca869f5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -59,6 +59,8 @@ protected: */ void reset(const std::string &start, const std::string &stop); + bool handleEvent(float time, const std::string &evt); + /* Specifies a list of skeleton names to use as animation sources. */ void setAnimationSources(const std::vector &names); From a5ff8181b737b91f096b1182f03066ac14ef0e06 Mon Sep 17 00:00:00 2001 From: lazydev Date: Sun, 24 Feb 2013 03:35:43 +0400 Subject: [PATCH 0446/1483] fix for https://bugs.openmw.org/issues/569 --- apps/openmw/mwworld/store.hpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index cb18873cc4..3eec052347 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -19,7 +19,7 @@ namespace MWWorld virtual int getSize() const = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; - + virtual bool eraseStatic(const std::string &id) {return false;} }; @@ -110,7 +110,7 @@ namespace MWWorld item.mId = Misc::StringUtils::lowerCase(id); typename std::map::const_iterator it = mStatic.find(item.mId); - + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { return &(it->second); } @@ -188,14 +188,14 @@ namespace MWWorld item.mId = Misc::StringUtils::lowerCase(id); typename std::map::iterator it = mStatic.find(item.mId); - + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { mStatic.erase(it); } return true; } - + bool erase(const std::string &id) { std::string key = Misc::StringUtils::lowerCase(id); typename Dynamic::iterator it = mDynamic.find(key); @@ -220,9 +220,15 @@ namespace MWWorld template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); - mStatic[idLower] = ESM::Dialogue(); - mStatic[idLower].mId = id; // don't smash case here, as this line is printed... I think - mStatic[idLower].load(esm); + + std::map::iterator it = mStatic.find(idLower); + if (it == mStatic.end()) { + it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; + it->second.mId = id; // don't smash case here, as this line is printed... I think + } + + //I am not sure is it need to load the dialog from a plugin if it was already loaded from prevois plugins + it->second.load(esm); } template <> @@ -409,7 +415,7 @@ namespace MWWorld DynamicInt mDynamicInt; DynamicExt mDynamicExt; - + const ESM::Cell *search(const ESM::Cell &cell) const { if (cell.isExterior()) { return search(cell.getGridX(), cell.getGridY()); @@ -481,7 +487,7 @@ namespace MWWorld newCell->mData.mY = y; mExt[std::make_pair(x, y)] = *newCell; delete newCell; - + return &mExt[std::make_pair(x, y)]; } @@ -528,7 +534,7 @@ namespace MWWorld // There some nasty three-way cyclic header dependency involved, which I could only fix by moving // this method. void load(ESM::ESMReader &esm, const std::string &id); - + iterator intBegin() const { return iterator(mSharedInt.begin()); } From 90cb9ee0ac73dca6388b2f69e1906945d51e4fab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 16:30:11 -0800 Subject: [PATCH 0447/1483] Don't set a vertical velocity when on the ground --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9b9c9afea2..0c1f580488 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -190,7 +190,7 @@ namespace MWWorld onground = false; } physicActor->setOnGround(onground); - physicActor->setVerticalForce(clippedVelocity.z - time*627.2f); + physicActor->setVerticalForce(!onground ? clippedVelocity.z - time*627.2f : 0.0f); return newPosition; } From 9198afeefb3a50bcefe3ff4f4f56d22e63f73b90 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 24 Feb 2013 03:10:27 +0100 Subject: [PATCH 0448/1483] Improved context menu, added context menu for masters and added multi-selection support --- apps/launcher/datafilespage.cpp | 186 ++++++++++++++++++++------------ apps/launcher/datafilespage.hpp | 9 +- 2 files changed, 119 insertions(+), 76 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 4ecb67e4e8..60e377afb7 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -99,9 +99,10 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersTable = new QTableView(this); mMastersTable->setModel(mMastersProxyModel); mMastersTable->setObjectName("MastersTable"); + mMastersTable->setContextMenuPolicy(Qt::CustomContextMenu); mMastersTable->setSortingEnabled(false); mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection); + mMastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); mMastersTable->setAlternatingRowColors(true); mMastersTable->horizontalHeader()->setStretchLastSection(true); @@ -118,7 +119,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); mPluginsTable->setSortingEnabled(false); mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mPluginsTable->setSelectionMode(QAbstractItemView::SingleSelection); + mPluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); mPluginsTable->setAlternatingRowColors(true); mPluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); @@ -173,6 +174,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(mMastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); @@ -208,15 +210,13 @@ void DataFilesPage::createActions() mProfileToolBar->addAction(mDeleteProfileAction); // Context menu actions - mCheckAction = new QAction(tr("Check selected"), this); + mCheckAction = new QAction(tr("Check Selection"), this); connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check())); - mUncheckAction = new QAction(tr("Uncheck selected"), this); + mUncheckAction = new QAction(tr("Uncheck Selection"), this); connect(mUncheckAction, SIGNAL(triggered()), this, SLOT(uncheck())); - // Context menu for the plugins table mContextMenu = new QMenu(this); - mContextMenu->addAction(mCheckAction); mContextMenu->addAction(mUncheckAction); } @@ -296,6 +296,9 @@ void DataFilesPage::loadSettings() void DataFilesPage::saveSettings() { + if (mDataFilesModel->rowCount() < 1) + return; + QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); if (profile.isEmpty()) @@ -406,54 +409,21 @@ void DataFilesPage::deleteProfile() void DataFilesPage::check() { - // Check the current selection - if (!mPluginsTable->selectionModel()->hasSelection()) { - return; - } + if (mPluginsTable->hasFocus()) + setPluginsCheckstates(Qt::Checked); - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + if (mMastersTable->hasFocus()) + setMastersCheckstates(Qt::Checked); - //sort selection ascending because selectedIndexes returns an unsorted list - //qSort(indexes.begin(), indexes.end(), rowSmallerThan); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); - - if (!sourceIndex.isValid()) - return; - - mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); - } } void DataFilesPage::uncheck() { - // uncheck the current selection - if (!mPluginsTable->selectionModel()->hasSelection()) { - return; - } + if (mPluginsTable->hasFocus()) + setPluginsCheckstates(Qt::Unchecked); - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); - - //sort selection ascending because selectedIndexes returns an unsorted list - //qSort(indexes.begin(), indexes.end(), rowSmallerThan); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); - - if (!sourceIndex.isValid()) - return; - - mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked); - } + if (mMastersTable->hasFocus()) + setMastersCheckstates(Qt::Unchecked); } void DataFilesPage::refresh() @@ -464,6 +434,50 @@ void DataFilesPage::refresh() mPluginsTable->scrollToTop(); } +void DataFilesPage::setMastersCheckstates(Qt::CheckState state) +{ + if (!mMastersTable->selectionModel()->hasSelection()) { + return; + } + + QModelIndexList indexes = mMastersTable->selectionModel()->selectedIndexes(); + + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + return; + + QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); + + if (!sourceIndex.isValid()) + return; + + mDataFilesModel->setCheckState(sourceIndex, state); + } +} + +void DataFilesPage::setPluginsCheckstates(Qt::CheckState state) +{ + if (!mPluginsTable->selectionModel()->hasSelection()) { + return; + } + + QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + return; + + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + mDataFilesModel->setCheckState(sourceIndex, state); + } +} void DataFilesPage::setCheckState(QModelIndex index) { @@ -554,35 +568,69 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre void DataFilesPage::showContextMenu(const QPoint &point) { - // Make sure there are plugins in the view - if (!mPluginsTable->selectionModel()->hasSelection()) { + QObject *object = QObject::sender(); + + // Not a signal-slot call + if (!object) return; - } - QPoint globalPos = mPluginsTable->mapToGlobal(point); - - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); - - // Show the check/uncheck actions depending on the state of the selected items - mUncheckAction->setEnabled(false); - mCheckAction->setEnabled(false); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) + if (object->objectName() == QLatin1String("PluginsTable")) { + if (!mPluginsTable->selectionModel()->hasSelection()) return; - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); + QPoint globalPos = mPluginsTable->mapToGlobal(point); + QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); - if (!sourceIndex.isValid()) - return; + // Show the check/uncheck actions depending on the state of the selected items + mUncheckAction->setEnabled(false); + mCheckAction->setEnabled(false); - (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mUncheckAction->setEnabled(true) - : mCheckAction->setEnabled(true); + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + return; + + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mUncheckAction->setEnabled(true) + : mCheckAction->setEnabled(true); + } + + // Show menu + mContextMenu->exec(globalPos); } - // Show menu - mContextMenu->exec(globalPos); + if (object->objectName() == QLatin1String("MastersTable")) { + if (!mMastersTable->selectionModel()->hasSelection()) + return; + QPoint globalPos = mMastersTable->mapToGlobal(point); + QModelIndexList indexes = mMastersTable->selectionModel()->selectedIndexes(); + + // Show the check/uncheck actions depending on the state of the selected items + mUncheckAction->setEnabled(false); + mCheckAction->setEnabled(false); + + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + return; + + QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); + + if (!sourceIndex.isValid()) + return; + + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mUncheckAction->setEnabled(true) + : mCheckAction->setEnabled(true); + } + + mContextMenu->exec(globalPos); + } } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 2561aa3d17..dd69d7489c 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -37,7 +37,6 @@ public: public slots: void setCheckState(QModelIndex index); - void filterChanged(const QString filter); void showContextMenu(const QPoint &point); void profileChanged(const QString &previous, const QString ¤t); @@ -49,10 +48,6 @@ public slots: // Action slots void newProfile(); void deleteProfile(); -// void moveUp(); -// void moveDown(); -// void moveTop(); -// void moveBottom(); void check(); void uncheck(); void refresh(); @@ -90,8 +85,8 @@ private: TextInputDialog *mNewProfileDialog; -// const QStringList checkedPlugins(); -// const QStringList selectedMasters(); + void setMastersCheckstates(Qt::CheckState state); + void setPluginsCheckstates(Qt::CheckState state); void createActions(); void setupDataFiles(); From be43fa334f88a4271d1201cd392d5f000f81aede Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 24 Feb 2013 03:14:19 +0100 Subject: [PATCH 0449/1483] Added support for non-latin characters, fixes Bug #515 --- apps/launcher/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index a5c6e30a5e..09da1d615f 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "maindialog.hpp" @@ -29,6 +30,9 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); + // Support non-latin characters + QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); + MainDialog mainWin; if (mainWin.setup()) { From 4737b20e4cf46f0bb7165fb4a1e1d2d013aedde0 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 24 Feb 2013 04:00:22 +0100 Subject: [PATCH 0450/1483] Fixed a bug in the combobox popup font size, items overlapping --- apps/launcher/playpage.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index cb993a8fa0..1dbc1b9dfd 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -15,10 +15,15 @@ PlayPage::PlayPage(QWidget *parent) : QWidget(parent) QLabel *profileLabel = new QLabel(tr("Current Profile:"), playWidget); profileLabel->setObjectName("ProfileLabel"); + // Hacks to get the stylesheet look properly on different platforms QPlastiqueStyle *style = new QPlastiqueStyle; + QFont font = QApplication::font(); + font.setPointSize(12); // Fixes problem with overlapping items + mProfilesComboBox = new QComboBox(playWidget); mProfilesComboBox->setObjectName("ProfilesComboBox"); mProfilesComboBox->setStyle(style); + mProfilesComboBox->setFont(font); QGridLayout *playLayout = new QGridLayout(playWidget); @@ -40,4 +45,4 @@ PlayPage::PlayPage(QWidget *parent) : QWidget(parent) pageLayout->addWidget(playWidget); -} \ No newline at end of file +} From 919d1ee5728cd15527d73e38a5b875d84ffdc171 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 24 Feb 2013 04:14:18 +0100 Subject: [PATCH 0451/1483] Some fixes to the settings handlers --- apps/launcher/settings/gamesettings.cpp | 19 ++++--------------- apps/launcher/settings/settingsbase.hpp | 8 -------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 6b46a5160b..c08179acce 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -88,7 +88,9 @@ bool GameSettings::readFile(QTextStream &stream) QString key = keyRe.cap(1).simplified(); QString value = keyRe.cap(2).simplified(); - mSettings.remove(key); + // Don't remove existing data entries + if (key != QLatin1String("data")) + mSettings.remove(key); QStringList values = cache.values(key); if (!values.contains(value)) { @@ -103,19 +105,6 @@ bool GameSettings::readFile(QTextStream &stream) return true; } - // Replace values from previous settings - QMapIterator i(cache); - while (i.hasNext()) { - i.next(); - - // Don't remove existing data entries - if (i.key() == QLatin1String("data")) - continue; - - if (mSettings.contains(i.key())) - mSettings.remove(i.key()); - } - // Merge the changed keys with those which didn't mSettings.unite(cache); validatePaths(); @@ -136,7 +125,7 @@ bool GameSettings::writeFile(QTextStream &stream) continue; // Quote paths with spaces - if (i.key() == QLatin1String("data") || i.key() == QLatin1String("data")) { + if (i.key() == QLatin1String("data")) { if (i.value().contains(" ")) { stream << i.key() << "=\"" << i.value() << "\"\n"; continue; diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 321426eed8..bbfad1fbb2 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -85,14 +85,6 @@ public: return true; } - // Replace values from previous settings - QMapIterator i(mCache); - while (i.hasNext()) { - i.next(); - if (mSettings.contains(i.key())) - mSettings.remove(i.key()); - } - // Merge the changed keys with those which didn't mSettings.unite(mCache); return true; From 0d6a3367d3693adc7d760b77ec1766c7ee532fbd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 10:28:50 +0100 Subject: [PATCH 0452/1483] Water shader no longer depends on object shaders being enabled --- apps/openmw/mwgui/settingswindow.cpp | 35 +++++++++++----------------- files/materials/water.mat | 4 +++- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 54c2ef197f..ebeb42ab2e 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -264,16 +264,9 @@ namespace MWGui mRefractionButton->setCaptionWithReplacing (Settings::Manager::getBool("refraction", "Water") ? "#{sOn}" : "#{sOff}"); - if (!MWRender::RenderingManager::waterShaderSupported()) - { - mWaterShaderButton->setEnabled(false); - mReflectObjectsButton->setEnabled(false); - mReflectActorsButton->setEnabled(false); - mReflectTerrainButton->setEnabled(false); - } - if (!Settings::Manager::getBool("shaders", "Objects")) { + mRefractionButton->setEnabled(false); mUnderwaterButton->setEnabled (false); mShadowsEnabledButton->setEnabled(false); } @@ -466,15 +459,15 @@ namespace MWGui { Settings::Manager::setBool("shaders", "Objects", false); - // water shader not supported with object shaders off - mWaterShaderButton->setCaptionWithReplacing("#{sOff}"); mUnderwaterButton->setCaptionWithReplacing("#{sOff}"); - mWaterShaderButton->setEnabled(false); - mReflectObjectsButton->setEnabled(false); - mReflectActorsButton->setEnabled(false); - mReflectTerrainButton->setEnabled(false); + mUnderwaterButton->setEnabled(false); - Settings::Manager::setBool("shader", "Water", false); + + // refraction needs shaders to display underwater fog + mRefractionButton->setCaptionWithReplacing("#{sOff}"); + mRefractionButton->setEnabled(false); + + Settings::Manager::setBool("refraction", "Water", false); Settings::Manager::setBool("underwater effect", "Water", false); // shadows not supported @@ -487,13 +480,11 @@ namespace MWGui Settings::Manager::setBool("shaders", "Objects", true); // re-enable - if (MWRender::RenderingManager::waterShaderSupported()) - { - mWaterShaderButton->setEnabled(true); - mReflectObjectsButton->setEnabled(true); - mReflectActorsButton->setEnabled(true); - mReflectTerrainButton->setEnabled(true); - } + mReflectObjectsButton->setEnabled(true); + mReflectActorsButton->setEnabled(true); + mReflectTerrainButton->setEnabled(true); + mRefractionButton->setEnabled(true); + mUnderwaterButton->setEnabled(true); mShadowsEnabledButton->setEnabled(true); } diff --git a/files/materials/water.mat b/files/materials/water.mat index 7546606fc3..372058f0ac 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -1,5 +1,7 @@ material Water { + allow_fixed_function false + pass { emissive 1.0 1.0 1.0 @@ -44,7 +46,7 @@ material Water tex_address_mode border tex_border_colour 0.5 0.5 1.0 } - + // for simple_water texture_unit animatedTexture { From 6a8c532244c901d6de89487e57cf6c611e1f8cc4 Mon Sep 17 00:00:00 2001 From: greye Date: Sun, 24 Feb 2013 14:59:21 +0400 Subject: [PATCH 0453/1483] fix and unify object cell change update in mwrender --- apps/openmw/mwrender/actors.cpp | 12 ++++++------ apps/openmw/mwrender/actors.hpp | 2 +- apps/openmw/mwrender/objects.cpp | 6 +++--- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 14 +++++--------- apps/openmw/mwrender/renderingmanager.hpp | 7 ++++--- apps/openmw/mwworld/worldimp.cpp | 3 ++- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 485e3a7adc..78521d0ce6 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -149,10 +149,10 @@ Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) return NULL; } -void Actors::updateObjectCell(const MWWorld::Ptr &ptr) +void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *node; - MWWorld::CellStore *newCell = ptr.getCell(); + MWWorld::CellStore *newCell = cur.getCell(); CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell); if(celliter != mCellSceneNodes.end()) @@ -162,15 +162,15 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) node = mMwRoot->createChildSceneNode(); mCellSceneNodes[newCell] = node; } - node->addChild(ptr.getRefData().getBaseNode()); + node->addChild(cur.getRefData().getBaseNode()); - PtrAnimationMap::iterator iter = mAllActors.find(ptr); + PtrAnimationMap::iterator iter = mAllActors.find(old); if(iter != mAllActors.end()) { Animation *anim = iter->second; mAllActors.erase(iter); - anim->updatePtr(ptr); - mAllActors[ptr] = anim; + anim->updatePtr(cur); + mAllActors[cur] = anim; } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index fc9fa4fbba..c89bfbaf5e 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -42,7 +42,7 @@ namespace MWRender void update (float duration); /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &ptr); + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); Animation* getAnimation(const MWWorld::Ptr &ptr); }; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index fe81eb9114..2bbb229a39 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -533,10 +533,10 @@ void Objects::rebuildStaticGeometry() } } -void Objects::updateObjectCell(const MWWorld::Ptr &ptr) +void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *node; - MWWorld::CellStore *newCell = ptr.getCell(); + MWWorld::CellStore *newCell = cur.getCell(); if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { node = mMwRoot->createChildSceneNode(); @@ -544,6 +544,6 @@ void Objects::updateObjectCell(const MWWorld::Ptr &ptr) } else { node = mCellSceneNodes[newCell]; } - node->addChild(ptr.getRefData().getBaseNode()); + node->addChild(cur.getRefData().getBaseNode()); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 283c053882..b7dd5a3b1a 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -95,7 +95,7 @@ public: void rebuildStaticGeometry(); /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &ptr); + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 0b9730dead..5dd2b37736 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -302,23 +302,19 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot } void -RenderingManager::moveObjectToCell( - const MWWorld::Ptr& ptr, - const Ogre::Vector3& pos, - MWWorld::CellStore *store) +RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *child = - mRendering.getScene()->getSceneNode(ptr.getRefData().getHandle()); + mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); Ogre::SceneNode *parent = child->getParentSceneNode(); parent->removeChild(child); - if (MWWorld::Class::get(ptr).isActor()) { - mActors.updateObjectCell(ptr); + if (MWWorld::Class::get(old).isActor()) { + mActors.updateObjectCell(old, cur); } else { - mObjects.updateObjectCell(ptr); + mObjects.updateObjectCell(old, cur); } - child->setPosition(pos); } void RenderingManager::update (float duration, bool paused) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b6c33f9c01..bdb5447e32 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -123,9 +123,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setWaterHeight(const float height); void toggleWater(); - /// Moves object rendering part to proper container - /// \param store Cell the object was in previously (\a ptr has already been updated to the new cell). - void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::CellStore *store); + /// Updates object rendering after cell change + /// \param old Object reference in previous cell + /// \param cur Object reference in new cell + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); void update (float duration, bool paused); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 71e956b6ed..f723934be9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -770,7 +770,8 @@ namespace MWWorld MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); - mRendering->moveObjectToCell(copy, vec, currCell); + mRendering->updateObjectCell(ptr, copy); + MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); mechMgr->updateCell(copy); From 89d4c245e9b2a8b5fff0afa1494ec5417fe67331 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 03:30:33 -0800 Subject: [PATCH 0454/1483] Better calculate jump velocity The fatigue term isn't currently used correctly --- apps/openmw/mwclass/npc.cpp | 41 +++++++++++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 8 ++++++ apps/openmw/mwmechanics/character.cpp | 24 ++++++++++++---- apps/openmw/mwworld/class.cpp | 5 ++++ apps/openmw/mwworld/class.hpp | 3 ++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 642c7f6453..12b40bfdcf 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -71,6 +71,11 @@ namespace MWClass fMaxFlySpeed = gmst.find("fMaxFlySpeed"); fSwimRunBase = gmst.find("fSwimRunBase"); fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult"); + fJumpEncumbranceBase = gmst.find("fJumpEncumbranceBase"); + fJumpEncumbranceMultiplier = gmst.find("fJumpEncumbranceMultiplier"); + fJumpAcrobaticsBase = gmst.find("fJumpAcrobaticsBase"); + fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier"); + fJumpRunMultiplier = gmst.find("fJumpRunMultiplier"); // Added in Tribunal/Bloodmoon, may not exist fWereWolfRunMult = gmst.search("fWereWolfRunMult"); @@ -371,6 +376,37 @@ namespace MWClass return moveSpeed; } + float Npc::getJump(const MWWorld::Ptr &ptr) const + { + const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); + const float encumbranceTerm = fJumpEncumbranceBase->getFloat() + + fJumpEncumbranceMultiplier->getFloat() * + (Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); + + float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); + float b = 0.0f; + if(a > 50.0f) + { + b = a - 50.0f; + a = 50.0f; + } + + float x = fJumpAcrobaticsBase->getFloat() + + std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat()); + x += 3 * b * fJumpAcroMultiplier->getFloat(); + x += mageffects.get(MWMechanics::EffectKey(9/*jump*/)).mMagnitude * 64; + x *= encumbranceTerm; + + if(Npc::getStance(ptr, Run, false)) + x *= fJumpRunMultiplier->getFloat(); + x *= 1.25f;//fatigueTerm; + x -= -627.2/*gravity constant*/; + x /= 3; + + return x; + } + MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const { ensureCustomData (ptr); @@ -496,5 +532,10 @@ namespace MWClass const ESM::GameSetting *Npc::fMaxFlySpeed; const ESM::GameSetting *Npc::fSwimRunBase; const ESM::GameSetting *Npc::fSwimRunAthleticsMult; + const ESM::GameSetting *Npc::fJumpEncumbranceBase; + const ESM::GameSetting *Npc::fJumpEncumbranceMultiplier; + const ESM::GameSetting *Npc::fJumpAcrobaticsBase; + const ESM::GameSetting *Npc::fJumpAcroMultiplier; + const ESM::GameSetting *Npc::fJumpRunMultiplier; const ESM::GameSetting *Npc::fWereWolfRunMult; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index a97e4c42ee..f41edb0df6 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -27,6 +27,11 @@ namespace MWClass static const ESM::GameSetting *fMaxFlySpeed; static const ESM::GameSetting *fSwimRunBase; static const ESM::GameSetting *fSwimRunAthleticsMult; + static const ESM::GameSetting *fJumpEncumbranceBase; + static const ESM::GameSetting *fJumpEncumbranceMultiplier; + static const ESM::GameSetting *fJumpAcrobaticsBase; + static const ESM::GameSetting *fJumpAcroMultiplier; + static const ESM::GameSetting *fJumpRunMultiplier; static const ESM::GameSetting *fWereWolfRunMult; public: @@ -81,6 +86,9 @@ namespace MWClass virtual float getSpeed (const MWWorld::Ptr& ptr) const; ///< Return movement speed. + virtual float getJump(const MWWorld::Ptr &ptr) const; + ///< Return jump velocity (not accounting for movement) + virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 37477932a4..8f7929805f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,11 +172,25 @@ Ogre::Vector3 CharacterController::update(float duration) bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); - // This jump is all kinds of wrong. The speed is incorrect, the state should be set to - // Jump, and X/Y movement should be disallowed except for the initial thrust (which would - // be carried by "physics" until landing). - if(onground) - movement.z += vec.z * (500.0f*duration); + /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except + * for the initial thrust (which would be carried by "physics" until landing). */ + if(onground && vec.z > 0.0f) + { + float x = cls.getJump(mPtr); + + if(vec.x == 0 && vec.y == 0) + movement.z += x*duration; + else + { + /* FIXME: this would be more correct if we were going into a jumping state, + * rather than normal walking/idle states. */ + //Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); + //movement += Ogre::Vector3(lat.x, lat.y, 1.0f) * x * 0.707f * duration; + movement.z += x * 0.707f * duration; + } + + //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult; + } if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c760191496..71b24b65dc 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -122,6 +122,11 @@ namespace MWWorld return 0; } + float Class::getJump (const Ptr& ptr) const + { + return 0; + } + MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const { throw std::runtime_error ("movement settings not supported by class"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 07dcb8fe03..1a6a16ca07 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -140,6 +140,9 @@ namespace MWWorld virtual float getSpeed (const Ptr& ptr) const; ///< Return movement speed. + virtual float getJump(const MWWorld::Ptr &ptr) const; + ///< Return jump velocity (not accounting for movement) + virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. From 62c5568ed9138eb679f0427a2ea655af872303eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Sun, 24 Feb 2013 16:57:07 +0100 Subject: [PATCH 0455/1483] Fix for the loadingbar to resemble vanilla Morrowind. --- files/mygui/openmw_loading_screen.layout | 4 ++-- files/mygui/openmw_progress.skin.xml | 13 +++++++++++++ files/mygui/smallbars.png | Bin 246 -> 3205 bytes 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 6862702ca1..4b6861151a 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -6,12 +6,12 @@ - + - + diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index c4b94e28e2..4666be2217 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -17,6 +17,11 @@
+ + + + + @@ -51,4 +56,12 @@ + + + + + + + +
diff --git a/files/mygui/smallbars.png b/files/mygui/smallbars.png index a9ed572ef6dd53092f3e35dd1fc871a60686e91d..f938412c259c540d8e085a339fa0d94c4294a361 100644 GIT binary patch literal 3205 zcmYjTc|6o>7k`GyzGatm$(rnIc4q8r7#UHv7$u?HY>_2fx+Gbr5tV&O)MzYaCo)3T zv1Ch#Zk9%vnRndoeRDpa=X-wNv;Lm*{Bx4dTAQ#k9b*Cju$q|~+EF!>dW0Ehs90ZR z%}7;@0j5qj0AS`iI1rHgh#vqZo6B(c*|R?WLH;*<`~!r|;Beu9>;B%CuX+IxGJ&y2 zA?%lVb%@hjFpI>fhZg>JJPg8iu;eK2Gzn=DMh^2tk%Dm^+m@q7Mo_`-{6yN6l&E_= zwlXYtna1cBM4qI?K25yavo{<5)OVzj__>e#YE*ZrViQx_Pv6YIl4+`Js~W{p3OjN1 zQ*2jz=j?)F_jo_I*hxb=E^%!9MCz)kY@=OGY<*~tlq0OyAy zJdpe}Ak5{JXb60?Kt=z#yG8)10Jyy^+BLwKEKo3W^fm?6b)Xr~!CV6vSb&0UV%#YJ z4F_)BqM{+-P7dHU-f-0Ze!7ZdNt!yToEmMMn1)fbGlOg(y`!Vt2`Ri8-)U|&cN+Ix zeYw`q908?h74}b??*Yh9fz$6cgo3IktG+>S_#DU>r=O!!?Qx9v%b zG*weYySoTs2UDR9o$E9j2`y2 z`dkHVL(;Zq|BGNKXS7i>qZ%|AChUH~z!YhTv>r1p5k4-aa&&@GosssAZL8$T^b(7g z67@%aw)1-^DJCFIWkg3fQ@P|h!V}@`>SCNpa3x9HeHybD&k%#0gT{l`>_nGkO3^B& z$3)ZLOkz-M1kUmgY0oLxhZ9)l`%AdI!eX+b|7KN2hGKP-%@c9rgKmQU`e{?G2 zgmu;j$HCrZlP_6cXt#n{SmSwOyAn}S0%(4Eew08k|MP6iB7vb~fi8rCy5ef~QVx5L zzXMVlD}9S6t%oVYJVPQwP+A^QT2@pxUB>LN>ClTvExl+TQDy9)Y(HPh_%XBGp$v0& z)n3pZRjO5zP=+e;N9a9^bRs3uIkj1~*}$LK=D%>AZ|oFi_7tcMkrDA_Esy^*TD4u` zMc??Xo6-&0B%y|6owCvb4Y;zovSY2?=0k5i`uXg@oku~|j7w6*S(}k}r@6nKnmZ*} zq+*Fv^m6en%go9|mYbH_mYb|Lsa35NV~U!L8l3i`*$leOC0!&A54 zVqPm9&Fw0=GT%bMf(FCjx7Ui-v-93ujLNh0FP;uPywE+vJ!|$(8g4-Q>9Fx%#_ablce>1r&HHuwbv~7# zlMs=xuv)QN&$Y9{6`d;5vedHd>U-b!q;Dig6|JKfFwUoR`6tU|)Ng z)hwJZa$3hWUW+@g;Z%rpIDetmxDrz-KGIOxP<*r)XPs_co;QMOtNxCChb^rWs9qeS zBUEAiuo3Pk4?a{~M^)Q;dQ*BteZ*fR9eUP;akg@y^Fom~US8+cJf}IGi+{AP7tyhm zxh#)D_H*=)DbHiMdQY`q#@M5WOi+9%+>O}H#N;H4m|nRoT{*O1=Tvvof_cz(;Dy<+ z!EFq>7Tvm5LU_Kewtjg%Ve;{NmB**@oRn{TXzPZ5vRxd|V}6{W;5$cvV;jUq(;WQeh zXru95)?8Iuw@mJe_Jn%9O1)mEoVU~aVI&4=cGcpzhMaVj+O?~1X7<-M6Xq~;%=6)V z+49{N0zwP$ty^)$yrpuSGMbtCmWkG99{z2>Azi|IPke(bSUiO(v{k4Tby9vnZ6I+B z?jn7{dc#!OD(u16v_{oXu@2=znMK?k$%JKeYTzP5*OU;WXy$CNeBR?gW6*ur=VM_D1{=cbA)8a3L1p#-LRo+GE@&(T$A zzrKr=_8Yb-Uvtc=ifobyv+|9;*wPcz@(SX+%Iv_j7#FcRIl6Yi1}X0}^U8fU9wVsB zlXSO=o4}XFb9+o`GGtLO!N2Ei&g8?FrRD9oOa0!1-pik-W%HcbGRv|)XR%#l9iMo~ zI&<#j+V&44f_zq=6rmv&3&%ZutNpsstN0zhPfHK+46%jSMX0S0PQ7v;-MKcfE*ReU zL*?r*!MTx0(tY=a-~e&38ulLc+B4g$CF)frl`ZdN?)hD)wDt>J>!KZ`CDDtrVMlQv zhlK`p5O%2}r&mqby8d`W#(WEwWmRK!`0G*UoM?by=)y9QafWz;RdeFzz3_@z`k_B= z3ZaDLufTFQa*fgUxqHqY&h<9$bq7XPro;A42!F6YQqgt_HQz+MyF9TRGn9_n=)Z@_ zz(hpK{hV|oJi&%9dE#fTu={_j=Lnh|G@>LgX*Fu$T{d0^ZPXAJxg1|R=04YS^;-#A z(I%%4*>p8LYRIj^x%lGN!ca&lF-&0wZaIk!On%Y?b5GD>lR4f2LDO9}-z@G{LthfQ7nGFD+{{z0IKN#_sIty(mx2@{Kfu>g|6+9{+|S0+dV|S z9wtMA*M5fq$ib@oOP~-M2n0eyp^&L~V5X1`YETinzq|Es5cPNVcE2AYJBP{c-@iS} z4y(Tj_}zxOqSHeFwKCO2rot|DLICU?AQb%AKa{h%dx-qKcZh5p@}Soa-SpSoNDyiV zGPFpdlA1%EB(*k_g&ok+P$vi>lK^y^2q*^)|7l91u5|wibnE+}Y8zjvFZZt;l%XW^ V+qrc3Ge{oT%#5rJt6*+1{{u-NeNq4b delta 212 zcmV;_04x868TJ8?7Z(}`0ssI2A5Ut+00001b5ch_0Itp)>5(B9e*gz`Nliru*#ZX- z6CpS#nr{FA0EkIMK~xyiZP3990znLg;Xh%(5~&##IK14YFH6+F=H0OkN?-L%E#W(hUno^d&x2M`?)6%mba5mg|}wqAOD zjaaLXgil6Y2Ck=DGTNi*9(IC(f}_*`XaN-7J;m0Vu(X6{noP6(|JxT0PCY1eTX63H O0000 Date: Sun, 24 Feb 2013 16:57:40 +0100 Subject: [PATCH 0456/1483] Prettier repeated borders. --- files/mygui/openmw_hud_box.skin.xml | 88 +++++++++++++++-------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index ce231e5bb9..464b6343aa 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -2,76 +2,78 @@ - - - + + + + - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + - - - + + + + - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - From 2e6c63d9cd255f45a7e6ec8b1c78bc7a652954e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 17:18:22 +0100 Subject: [PATCH 0457/1483] Disable specular on NIF's --- components/nifogre/ogre_nif_loader.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c3bbc141bf..27926b7c4b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -575,9 +575,17 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String { ambient = m->data.ambient; diffuse = m->data.diffuse; - specular = m->data.specular; emissive = m->data.emissive; - glossiness = m->data.glossiness; + + + // Vanilla does not handle specular. TODO: Add an engine (or ESX file) configuration option + // to re-enable specular for future mods. Will also need to specify light specular colors somewhere. + // Also, not sure if glossiness value here is actually correct. OGRE expects 0-255 value, not sure what range this one is. + //glossiness = m->data.glossiness; + //specular = m->data.specular; + glossiness = 0; + specular = Ogre::Vector3(0,0,0); + alpha = m->data.alpha; } From 7ea1f6a02a06e83a153ff85c7f3b5ab210c37ca7 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 00:23:10 -0800 Subject: [PATCH 0458/1483] fixes for using FFMPEG on windows --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 4 ++++ cmake/FindFFmpeg.cmake | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 00530a9628..54df45ff4c 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -153,6 +153,10 @@ void FFmpeg_Decoder::open(const std::string &fname) try { + for(size_t j = 0;j < mFormatCtx->nb_streams;j++) + if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) + mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; + if(avformat_find_stream_info(mFormatCtx, NULL) < 0) fail("Failed to find stream info in "+fname); diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index c80203a25b..4147590d60 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -68,6 +68,7 @@ macro(find_component _component _pkgconfig _library _header) find_path(${_component}_INCLUDE_DIRS ${_header} HINTS + ${FFMPEGSDK_INC} ${PC_LIB${_component}_INCLUDEDIR} ${PC_LIB${_component}_INCLUDE_DIRS} PATH_SUFFIXES @@ -76,6 +77,7 @@ macro(find_component _component _pkgconfig _library _header) find_library(${_component}_LIBRARIES NAMES ${_library} HINTS + ${FFMPEGSDK_LIB} ${PC_LIB${_component}_LIBDIR} ${PC_LIB${_component}_LIBRARY_DIRS} ) @@ -97,6 +99,12 @@ endmacro() # Check for cached results. If there are skip the costly part. if (NOT FFMPEG_LIBRARIES) + set (FFMPEGSDK ENV${FFMPEG_HOME}) + if (FFMPEGSDK) + set (FFMPEGSDK_INC "${FFMPEGSDK}/include") + set (FFMPEGSDK_LIB "${FFMPEGSDK}/lib") + endif () + # Check for all possible component. find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) find_component(AVFORMAT libavformat avformat libavformat/avformat.h) From 1ae2d3c6abd06cb76b151067c88a0b5d3a9090a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 19:00:06 +0100 Subject: [PATCH 0459/1483] For light objects without an AttachLight bone, attach the light to the center of the object instead of the origin. --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwrender/objects.cpp | 17 ++++++++++++++--- apps/openmw/mwrender/objects.hpp | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 9d0fe298b0..c23e4b833d 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -38,7 +38,7 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); else - objects.insertLight(ptr, NULL); + objects.insertLight(ptr, NULL, Ogre::Vector3(0,0,0)); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index c51cafc0e1..06ddcb2256 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -49,6 +49,12 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) node->detachObject (object); mRenderer.getScene()->destroyMovableObject (object); } + + Ogre::Node::ChildNodeIterator it = node->getChildIterator (); + while (it.hasMoreElements ()) + { + clearSceneNode(static_cast(it.getNext ())); + } } void Objects::setMwRoot(Ogre::SceneNode* root) @@ -219,11 +225,11 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool if (light) { - insertLight(ptr, entities.mSkelBase); + insertLight(ptr, entities.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); } } -void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) +void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter) { Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle()); assert(insert); @@ -291,9 +297,14 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight")) + { skelBase->attachObjectToBone ("AttachLight", light); + } else - insert->attachObject(light); + { + Ogre::SceneNode* childNode = insert->createChildSceneNode (fallbackCenter); + childNode->attachObject(light); + } mLights.push_back(info); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 283c053882..1a4829d9f4 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -74,7 +74,7 @@ public: ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); - void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter); void enableLights(); void disableLights(); From f1a33093922a8f16a05e98af5b86c05eed9743f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 19:03:25 +0100 Subject: [PATCH 0460/1483] forgot to destroy child scene nodes --- apps/openmw/mwrender/objects.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 06ddcb2256..53957152f6 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -55,6 +55,7 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) { clearSceneNode(static_cast(it.getNext ())); } + node->removeAndDestroyAllChildren (); } void Objects::setMwRoot(Ogre::SceneNode* root) From e060713aa350b110c7b9e55f768c558048727d48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Feb 2013 20:37:29 +0100 Subject: [PATCH 0461/1483] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 8b396aad0a..535e922ae1 100644 --- a/credits.txt +++ b/credits.txt @@ -29,6 +29,7 @@ Jannik Heller (scrawl) Jason Hooks (jhooks) Joel Graff (graffy) Karl-Felix Glatzer (k1ll) +Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) From c60e858b0216c5d444db16b7c2eb5003f3886df1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 12:42:32 -0800 Subject: [PATCH 0462/1483] Create bones for NiTriShape nodes, and attach the entities to them Otherwise some models don't connect properly. NiTriShapes are more guaranteed to have unique names than their parent nodes. --- components/nifogre/ogre_nif_loader.cpp | 26 ++++++-------------------- components/nifogre/ogre_nif_loader.hpp | 8 ++------ 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c52a73e1c1..8c5d4dc5ac 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -303,9 +303,6 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { - if(node->recType == Nif::RC_NiTriShape) - return; - Ogre::Bone *bone; if(!skel->hasBone(node->name)) bone = skel->createBone(node->name); @@ -319,7 +316,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro bone->setBindingPose(); if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_NiTriShape /* Handled in the mesh loader */ )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); @@ -1073,8 +1071,7 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), - shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); + meshes.push_back(MeshInfo(mesh->getName(), shape->name)); } const Nif::NiNode *ninode = dynamic_cast(node); @@ -1108,8 +1105,7 @@ public: mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), (node->parent ? node->parent->name : node->name), - node->trafo.pos, node->trafo.rotation, node->trafo.scale)); + meshes.push_back(MeshInfo(mesh->getName(), node->name)); } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; @@ -1190,12 +1186,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) - { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - tag->setPosition(meshes[i].mPos); - tag->setOrientation(meshes[i].mRot); - tag->setScale(Ogre::Vector3(meshes[i].mScale)); - } + entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); } } else @@ -1248,12 +1239,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen else { if(entity->getMesh()->getName().find(filter) != std::string::npos) - { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - tag->setPosition(meshes[i].mPos); - tag->setOrientation(meshes[i].mRot); - tag->setScale(Ogre::Vector3(meshes[i].mScale)); - } + entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); } } } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 0064defe29..7a7b0c5a1e 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -53,13 +53,9 @@ struct EntityList { struct MeshInfo { std::string mMeshName; std::string mTargetNode; - Ogre::Vector3 mPos; - Ogre::Matrix3 mRot; - float mScale; - MeshInfo(const std::string &name, const std::string &target, - const Ogre::Vector3 &pos, const Ogre::Matrix3 &rot, float scale) - : mMeshName(name), mTargetNode(target), mPos(pos), mRot(rot), mScale(scale) + MeshInfo(const std::string &name, const std::string &target) + : mMeshName(name), mTargetNode(target) { } }; typedef std::vector MeshInfoList; From 5267d17408017e2f0be488de05aa4b683b7852a1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 14:14:08 -0800 Subject: [PATCH 0463/1483] Revert "forgot to destroy child scene nodes" This reverts commit f1a33093922a8f16a05e98af5b86c05eed9743f6. Unneeded. The caller already calls this which destroys the children recursively --- apps/openmw/mwrender/objects.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9e79f02561..76f38eefc2 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -55,7 +55,6 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) { clearSceneNode(static_cast(it.getNext ())); } - node->removeAndDestroyAllChildren (); } void Objects::setMwRoot(Ogre::SceneNode* root) From 74b8095fc70dd66027aebe8da081cc9cf3aae21c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 14:43:20 -0800 Subject: [PATCH 0464/1483] Use default parameters where appropriate --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwrender/objects.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c23e4b833d..200f6e2d4a 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -38,7 +38,7 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); else - objects.insertLight(ptr, NULL, Ogre::Vector3(0,0,0)); + objects.insertLight(ptr); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index e0b53f9063..5801014642 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -74,7 +74,7 @@ public: ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); - void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f)); void enableLights(); void disableLights(); From 17a0a201dfe0281a8600fe30742bcd3e77ce9722 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 00:56:04 +0100 Subject: [PATCH 0465/1483] Various fixes and changes to the settings handling --- apps/launcher/datafilespage.cpp | 35 ++++++--------------- apps/launcher/graphicspage.cpp | 2 +- apps/launcher/settings/gamesettings.cpp | 32 +++++++++++++++++-- apps/launcher/settings/launchersettings.cpp | 8 +++++ 4 files changed, 48 insertions(+), 29 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 60e377afb7..a0df2fb828 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -19,23 +19,6 @@ #include "datafilespage.hpp" -#include -/** - * Workaround for problems with whitespaces in paths in older versions of Boost library - */ -#if (BOOST_VERSION <= 104600) -namespace boost -{ - - template<> - inline boost::filesystem::path lexical_cast(const std::string& arg) - { - return boost::filesystem::path(arg); - } - -} /* namespace boost */ -#endif /* (BOOST_VERSION <= 104600) */ - using namespace ESM; using namespace std; @@ -241,7 +224,7 @@ void DataFilesPage::setupDataFiles() mDataFilesModel->sort(3); QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); - QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); mProfilesComboBox->setCurrentIndex(-1); mProfilesComboBox->addItems(profiles); @@ -271,7 +254,7 @@ void DataFilesPage::setupDataFiles() void DataFilesPage::loadSettings() { - QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); if (profile.isEmpty()) return; @@ -299,10 +282,12 @@ void DataFilesPage::saveSettings() if (mDataFilesModel->rowCount() < 1) return; - QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); - if (profile.isEmpty()) - return; + if (profile.isEmpty()) { + profile = mProfilesComboBox->currentText(); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile); + } mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); @@ -539,9 +524,9 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre return; // Profile was deleted // Store the previous profile - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), previous); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), previous); saveSettings(); - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), current); loadSettings(); } @@ -552,7 +537,7 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre return; // Save the new profile name - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), current); saveSettings(); // Remove the old one diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 49002e87e2..b5a00b14c5 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -196,7 +196,7 @@ void GraphicsPage::loadSettings() resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); - qDebug() << "resolution from file: " << resolution; + if (resIndex != -1) mResolutionComboBox->setCurrentIndex(resIndex); } diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index c08179acce..af78757b73 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -8,6 +8,23 @@ #include +#include +/** + * Workaround for problems with whitespaces in paths in older versions of Boost library + */ +#if (BOOST_VERSION <= 104600) +namespace boost +{ + + template<> + inline boost::filesystem::path lexical_cast(const std::string& arg) + { + return boost::filesystem::path(arg); + } + +} /* namespace boost */ +#endif /* (BOOST_VERSION <= 104600) */ + #include "gamesettings.hpp" GameSettings::GameSettings(Files::ConfigurationManager &cfg) @@ -93,6 +110,8 @@ bool GameSettings::readFile(QTextStream &stream) mSettings.remove(key); QStringList values = cache.values(key); + values.append(mSettings.values(key)); + if (!values.contains(value)) { cache.insertMulti(key, value); } @@ -125,9 +144,16 @@ bool GameSettings::writeFile(QTextStream &stream) continue; // Quote paths with spaces - if (i.key() == QLatin1String("data")) { - if (i.value().contains(" ")) { - stream << i.key() << "=\"" << i.value() << "\"\n"; + if (i.key() == QLatin1String("data") + || i.key() == QLatin1String("data-local") + || i.key() == QLatin1String("resources")) + { + if (i.value().contains(QChar(' '))) + { + QString stripped = i.value(); + stripped.remove(QChar('\"')); // Remove quotes + + stream << i.key() << "=\"" << stripped << "\"\n"; continue; } } diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index e9730c2357..ee529d8912 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -66,6 +66,7 @@ bool LauncherSettings::writeFile(QTextStream &stream) QString sectionPrefix; QRegExp sectionRe("([^/]+)/(.+)$"); QMap settings = SettingsBase::getSettings(); + qDebug() << "writing " << settings; QMapIterator i(settings); i.toBack(); @@ -81,6 +82,13 @@ bool LauncherSettings::writeFile(QTextStream &stream) key = sectionRe.cap(2); } + // Get rid of legacy settings + if (key.contains(QChar('\\'))) + continue; + + if (key == QLatin1String("CurrentProfile")) + continue; + if (sectionPrefix != prefix) { sectionPrefix = prefix; stream << "\n[" << prefix << "]\n"; From b1381ddd693995d4920a0e683b313ed46869bf6f Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Mon, 25 Feb 2013 04:12:41 +0400 Subject: [PATCH 0466/1483] Nif loader: workaround for missed textures in BB/BH Works for Better Bodies / Better Heads addons. --- components/nifogre/ogre_nif_loader.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index dfbc93ee90..0ee778df30 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -540,7 +540,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String Nif::NiSourceTexture *st = t->textures[0].texture.getPtr(); if (st->external) { - /* Bethesda at some at some point converted all their BSA + /* Bethesda 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. */ @@ -559,6 +559,17 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) texName = path + st->filename; } + else if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + { + // workaround for Better Heads addon + size_t lastSlash = st->filename.rfind('\\'); + if (lastSlash != std::string::npos && lastSlash + 1 != st->filename.size()) { + texName = path + st->filename.substr(lastSlash + 1); + // workaround for Better Bodies addon + if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + texName = st->filename; + } + } } else warn("Found internal texture, ignoring."); } From a0007325ad7a2d4eb1af4328fe7f185586340c62 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 01:22:14 +0100 Subject: [PATCH 0467/1483] Added a warning when stylesheet cannot be read and check if data paths contain masters/plugins --- apps/launcher/datafilespage.cpp | 4 +- apps/launcher/maindialog.cpp | 42 +++++++++++++++------ apps/launcher/settings/graphicssettings.cpp | 2 - apps/launcher/settings/launchersettings.cpp | 1 - apps/launcher/utils/checkablemessagebox.cpp | 1 - apps/launcher/utils/profilescombobox.cpp | 3 -- apps/launcher/utils/textinputdialog.cpp | 1 - 7 files changed, 33 insertions(+), 21 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index a0df2fb828..f8ccf3e83f 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -226,8 +226,8 @@ void DataFilesPage::setupDataFiles() QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); - mProfilesComboBox->setCurrentIndex(-1); - mProfilesComboBox->addItems(profiles); + if (!profiles.isEmpty()) + mProfilesComboBox->addItems(profiles); // Add the current profile if empty if (mProfilesComboBox->findText(profile) == -1) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c03a31fd59..c1e70bb3fa 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -78,10 +78,20 @@ MainDialog::MainDialog() file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string())); } - file.open(QFile::ReadOnly); - QString styleSheet = QLatin1String(file.readAll()); - qApp->setStyleSheet(styleSheet); - file.close(); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening Launcher stylesheet")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + } else { + QString styleSheet = QLatin1String(file.readAll()); + qApp->setStyleSheet(styleSheet); + file.close(); + } connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); @@ -261,7 +271,6 @@ bool MainDialog::showFirstRunDialog() // Add a new profile if (msgBox.isChecked()) { - qDebug() << "add a new profile"; mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), QString("Imported")); mLauncherSettings.remove(QString("Profiles/Imported/master")); @@ -330,7 +339,7 @@ bool MainDialog::setupLauncherSettings() paths.append(userPath + QString("launcher.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; + qDebug() << "Loading config file:" << qPrintable(path); QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -366,7 +375,8 @@ bool MainDialog::setupGameSettings() paths.append(globalPath + QString("openmw.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; + qDebug() << "Loading config file:" << qPrintable(path); + QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -388,7 +398,19 @@ bool MainDialog::setupGameSettings() file.close(); } - if (mGameSettings.getDataDirs().isEmpty()) + QStringList dataDirs; + + // Check if the paths actually contain data files + foreach (const QString path, mGameSettings.getDataDirs()) { + QDir dir(path); + QStringList filters; + filters << "*.esp" << "*.esm"; + + if (!dir.entryList(filters).isEmpty()) + dataDirs.append(path); + } + + if (dataDirs.isEmpty()) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Error detecting Morrowind installation")); @@ -415,13 +437,11 @@ bool MainDialog::setupGameSettings() if (selectedFile.isEmpty()) return false; // Cancel was clicked; - qDebug() << selectedFile; QFileInfo info(selectedFile); // Add the new dir to the settings file and to the data dir container mGameSettings.setValue(QString("data"), info.absolutePath()); mGameSettings.addDataDir(info.absolutePath()); - } return true; @@ -454,7 +474,7 @@ bool MainDialog::setupGraphicsSettings() paths.append(userPath + QString("settings.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; + qDebug() << "Loading config file:" << qPrintable(path); QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp index fd70917b5d..a92477ebbc 100644 --- a/apps/launcher/settings/graphicssettings.cpp +++ b/apps/launcher/settings/graphicssettings.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "graphicssettings.hpp" GraphicsSettings::GraphicsSettings() diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index ee529d8912..1101a80b95 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -66,7 +66,6 @@ bool LauncherSettings::writeFile(QTextStream &stream) QString sectionPrefix; QRegExp sectionRe("([^/]+)/(.+)$"); QMap settings = SettingsBase::getSettings(); - qDebug() << "writing " << settings; QMapIterator i(settings); i.toBack(); diff --git a/apps/launcher/utils/checkablemessagebox.cpp b/apps/launcher/utils/checkablemessagebox.cpp index 990835594b..41207a8ded 100644 --- a/apps/launcher/utils/checkablemessagebox.cpp +++ b/apps/launcher/utils/checkablemessagebox.cpp @@ -29,7 +29,6 @@ #include "checkablemessagebox.hpp" -#include #include #include diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp index 4c258dae60..c3ff953ae0 100644 --- a/apps/launcher/utils/profilescombobox.cpp +++ b/apps/launcher/utils/profilescombobox.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include @@ -67,8 +66,6 @@ void ProfilesComboBox::slotEditingFinished() QString current = currentText(); QString previous = itemText(currentIndex()); - qDebug() << current << previous; - if (currentIndex() == -1) return; diff --git a/apps/launcher/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp index 09b26ae75a..011e51bf25 100644 --- a/apps/launcher/utils/textinputdialog.cpp +++ b/apps/launcher/utils/textinputdialog.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include From c4ebdc230c4ed65a6d6d6be7d212376ad4ba0ccf Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 01:28:13 +0100 Subject: [PATCH 0468/1483] Cleaned up strings and indentation --- apps/launcher/maindialog.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c1e70bb3fa..c91ffa070e 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -60,22 +60,22 @@ MainDialog::MainDialog() // Check if the font is installed if (!fonts.contains("EB Garamond")) { - QString font = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); - file.setFileName(font); + QString font = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf"); + file.setFileName(font); - if (!file.exists()) { - font = QString::fromStdString((mCfgMgr.getLocalPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); - } + if (!file.exists()) { + font = QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf"); + } - fontDatabase.addApplicationFont(font); + fontDatabase.addApplicationFont(font); } // Load the stylesheet - QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string()); + QString config = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/launcher.qss"); file.setFileName(config); if (!file.exists()) { - file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string())); + file.setFileName(QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("launcher.qss")); } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { From 53eb553c57b69f7ce7bbf36159348724bab184df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 18:12:15 -0800 Subject: [PATCH 0469/1483] Be a little more aggressive when looking to skip generating a skeleton This is needed to handle the insane number of nodes and trishapes in in_prison_ship.nif, as Ogre has a 256-bone limit for skeletons. This is a bit sketchy, but it works. --- components/nifogre/ogre_nif_loader.cpp | 40 ++++++++++++++++---------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8c5d4dc5ac..1582826b81 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -454,23 +454,33 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { - /* If the root node is a NiTriShape, or is a parent to only NiTriShapes, do - * not create a skeleton. */ - if(node->recType == Nif::RC_NiTriShape) - return false; - - if(node->recType == Nif::RC_NiNode) + /* We need to be a little aggressive here, since some NIFs have a crap-ton + * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: + * There are no bones used for skinning, there are no controllers on non- + * NiTriShape nodes, there are no nodes named "AttachLight", and the tree + * consists of NiNode, NiTriShape, and RootCollisionNode types only. + */ + if(!node->boneTrafo) { - bool alltrishapes = true; - const Nif::NiNode *ninode = static_cast(node); - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length() && alltrishapes;i++) - { - if(!children[i].empty() && children[i]->recType != Nif::RC_NiTriShape) - alltrishapes = false; - } - if(alltrishapes) + if(node->recType == Nif::RC_NiTriShape) return false; + if(node->controller.empty() && node->name != "AttachLight") + { + if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) + { + const Nif::NiNode *ninode = static_cast(node); + 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())) + return true; + } + } + return false; + } + } } Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); From dfe29db9cb7cb811c3aef9ceb0b977af2f3d4f35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 06:57:32 +0100 Subject: [PATCH 0470/1483] Fix bug #591: Don't allow opening new windows (main menu, console) if there's any modal widget active. Also made some windows modal that should be (character creation) --- apps/openmw/mwgui/birth.cpp | 4 ++-- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/class.cpp | 10 ++++++---- apps/openmw/mwgui/class.hpp | 8 ++++---- apps/openmw/mwgui/race.cpp | 4 +++- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/review.cpp | 3 ++- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/text_input.cpp | 3 ++- apps/openmw/mwgui/text_input.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++++ 11 files changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index c53a68cf44..53e5c022d2 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -25,7 +25,7 @@ bool sortBirthSigns(const std::pair& left, c } BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_birth.layout", parWindowManager) + : WindowModal("openmw_chargen_birth.layout", parWindowManager) { // Centre dialog center(); @@ -66,7 +66,7 @@ void BirthDialog::setNextButtonShow(bool shown) void BirthDialog::open() { - WindowBase::open(); + WindowModal::open(); updateBirths(); updateSpells(); } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index f16f92325b..ad1c0b40f5 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -10,7 +10,7 @@ namespace MWGui { - class BirthDialog : public WindowBase + class BirthDialog : public WindowModal { public: BirthDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 2eed21a528..f3bac898b2 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -21,7 +21,7 @@ using namespace MWGui; /* GenerateClassResultDialog */ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_generate_class_result.layout", parWindowManager) + : WindowModal("openmw_chargen_generate_class_result.layout", parWindowManager) { // Centre dialog center(); @@ -68,7 +68,7 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) /* PickClassDialog */ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_class.layout", parWindowManager) + : WindowModal("openmw_chargen_class.layout", parWindowManager) { // Centre dialog center(); @@ -122,6 +122,7 @@ void PickClassDialog::setNextButtonShow(bool shown) void PickClassDialog::open() { + WindowModal::open (); updateClasses(); updateStats(); } @@ -276,7 +277,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) } InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_infobox.layout", parWindowManager) + : WindowModal("openmw_infobox.layout", parWindowManager) , mCurrentButton(-1) { getWidget(mTextBox, "TextBox"); @@ -327,6 +328,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons) void InfoBoxDialog::open() { + WindowModal::open(); // Fix layout layoutVertically(mTextBox, 4); layoutVertically(mButtonBar, 6); @@ -373,7 +375,7 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) /* CreateClassDialog */ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_create_class.layout", parWindowManager) + : WindowModal("openmw_chargen_create_class.layout", parWindowManager) , mSpecDialog(nullptr) , mAttribDialog(nullptr) , mSkillDialog(nullptr) diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index c7699b3083..2662d94ccf 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -12,7 +12,7 @@ namespace MWGui { - class InfoBoxDialog : public WindowBase + class InfoBoxDialog : public WindowModal { public: InfoBoxDialog(MWBase::WindowManager& parWindowManager); @@ -63,7 +63,7 @@ namespace MWGui ClassChoiceDialog(MWBase::WindowManager& parWindowManager); }; - class GenerateClassResultDialog : public WindowBase + class GenerateClassResultDialog : public WindowModal { public: GenerateClassResultDialog(MWBase::WindowManager& parWindowManager); @@ -90,7 +90,7 @@ namespace MWGui std::string mCurrentClassId; }; - class PickClassDialog : public WindowBase + class PickClassDialog : public WindowModal { public: PickClassDialog(MWBase::WindowManager& parWindowManager); @@ -238,7 +238,7 @@ namespace MWGui MyGUI::EditPtr mTextEdit; }; - class CreateClassDialog : public WindowBase + class CreateClassDialog : public WindowModal { public: CreateClassDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 054cce7b85..699c687ff6 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -20,7 +20,7 @@ using namespace MWGui; using namespace Widgets; RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_race.layout", parWindowManager) + : WindowModal("openmw_chargen_race.layout", parWindowManager) , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) @@ -100,6 +100,8 @@ void RaceDialog::setNextButtonShow(bool shown) void RaceDialog::open() { + WindowModal::open(); + updateRaces(); updateSkills(); updateSpellPowers(); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index e0dc3306a8..6195569065 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -23,7 +23,7 @@ namespace MWGui namespace MWGui { - class RaceDialog : public WindowBase + class RaceDialog : public WindowModal { public: RaceDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 45adb53832..50dc26e428 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -23,7 +23,7 @@ using namespace Widgets; const int ReviewDialog::sLineHeight = 18; ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_review.layout", parWindowManager) + : WindowModal("openmw_chargen_review.layout", parWindowManager) , mLastPos(0) { // Centre dialog @@ -97,6 +97,7 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) void ReviewDialog::open() { + WindowModal::open(); updateSkillArea(); } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 2b0740234e..aac609a646 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -17,7 +17,7 @@ Layout is defined by resources/mygui/openmw_chargen_review.layout. namespace MWGui { - class ReviewDialog : public WindowBase + class ReviewDialog : public WindowModal { public: enum Dialogs { diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 3dbe751659..c193948330 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -5,7 +5,7 @@ using namespace MWGui; TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_text_input.layout", parWindowManager) + : WindowModal("openmw_text_input.layout", parWindowManager) { // Centre dialog center(); @@ -39,6 +39,7 @@ void TextInputDialog::setTextLabel(const std::string &label) void TextInputDialog::open() { + WindowModal::open(); // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp index 8483103691..6499902815 100644 --- a/apps/openmw/mwgui/text_input.hpp +++ b/apps/openmw/mwgui/text_input.hpp @@ -13,7 +13,7 @@ namespace MWGui namespace MWGui { - class TextInputDialog : public WindowBase + class TextInputDialog : public WindowModal { public: TextInputDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f1f88b9aec..0ce664c9bf 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -521,6 +521,9 @@ namespace MWInput void InputManager::toggleMainMenu() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) mWindows.popGuiMode(); else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) @@ -599,6 +602,9 @@ namespace MWInput void InputManager::toggleConsole() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + bool gameMode = !mWindows.isGuiMode(); // Switch to console mode no matter what mode we are currently From 151ecaad049411e42fde0de45e36b7dd2bee27aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Feb 2013 10:32:38 +0100 Subject: [PATCH 0471/1483] workaround for garbage after an end statement --- components/compiler/fileparser.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 9b184f1ffb..98be2d3d1f 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -45,7 +45,10 @@ namespace Compiler reportWarning ("Names for script " + mName + " do not match", loc); mState = EndCompleteState; - return true; + return false; // we are stopping here, because there might be more garbage on the end line, + // that we must ignore. + // + /// \todo allow this workaround to be disabled for newer scripts } return Parser::parseName (name, loc, scanner); From 73d48a95f65ea68e1527ccd056362a855ae73619 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 16:31:48 +0100 Subject: [PATCH 0472/1483] Add message box when the player tries to move when being overencumbered. --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 25 +++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 +++--- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4f7435fadc..81d7cb9fed 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -198,7 +198,7 @@ namespace MWBase virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; ///< Hides dialog and schedules dialog to be deleted. - virtual void messageBox (const std::string& message, const std::vector& buttons) = 0; + virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector()) = 0; virtual void enterPressed () = 0; virtual int readPressedButton() = 0; ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index fff627366e..f574211372 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -188,7 +188,7 @@ namespace MWGui virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. - virtual void messageBox (const std::string& message, const std::vector& buttons); + virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector()); virtual void enterPressed (); virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5a4c431f58..4a79f77b85 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -21,6 +21,7 @@ #include "../engine.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -51,6 +52,7 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) + , mOverencumberedMessageDelay(0.f) { Ogre::RenderWindow* window = ogre.getWindow (); size_t windowHnd; @@ -268,13 +270,16 @@ namespace MWInput // be done in the physics system. if (mControlSwitch["playercontrols"]) { + bool triedToMove = false; if (actionIsActive(A_MoveLeft)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setLeftRight (1); } @@ -283,11 +288,13 @@ namespace MWInput if (actionIsActive(A_MoveForward)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setForwardBackward (1); } else if (actionIsActive(A_MoveBackward)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setForwardBackward (-1); } @@ -295,7 +302,10 @@ namespace MWInput mPlayer.setForwardBackward (0); if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) + { mPlayer.setUpDown (1); + triedToMove = true; + } else if (actionIsActive(A_Crouch)) mPlayer.setUpDown (-1); else @@ -306,6 +316,21 @@ namespace MWInput else mPlayer.setRunState(false); + // if player tried to start moving, but can't (due to being overencumbered), display a notification. + if (triedToMove) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); + mOverencumberedMessageDelay -= dt; + if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) + { + if (mOverencumberedMessageDelay <= 0) + { + MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); + mOverencumberedMessageDelay = 1.0; + } + } + } + if (mControlSwitch["playerviewswitch"]) { // work around preview mode toggle when pressing Alt+Tab diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 3af39911cb..383fe30359 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -145,6 +145,8 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + float mOverencumberedMessageDelay; + float mMouseX; float mMouseY; int mMouseWheel; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index eee72f8805..3cc3dcde39 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -491,8 +491,10 @@ namespace MWMechanics if(buying) x = buyTerm; else x = std::min(buyTerm, sellTerm); int offerPrice; - if (x < 1) offerPrice = int(x * basePrice); - if (x >= 1) offerPrice = basePrice + int((x - 1) * basePrice); + if (x < 1) + offerPrice = int(x * basePrice); + else + offerPrice = basePrice + int((x - 1) * basePrice); offerPrice = std::max(1, offerPrice); return offerPrice; } @@ -555,7 +557,7 @@ namespace MWMechanics float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); - float x,y; + float x,y = 0; float roll = static_cast (std::rand()) / RAND_MAX * 100; From 5d5d28c06ccabbbeae221a8eb4d906aeebc69b79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 07:43:56 -0800 Subject: [PATCH 0473/1483] Increase the ID cache to 40 Helps improve performance with Tribunal and Bloodmoon's scripts --- apps/openmw/mwworld/cells.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 59c62e37d6..b912f5ccca 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -86,7 +86,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector& reader) : mStore (store), mReader (reader), - mIdCache (20, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable + mIdCache (40, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable mIdCacheIndex (0) {} From 88e8659a4959b9dcf0670796f75af6cac8b3b9f4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Feb 2013 16:52:31 +0100 Subject: [PATCH 0474/1483] minor cleanup --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3cc3dcde39..5ed3770fd4 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -557,7 +557,8 @@ namespace MWMechanics float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); - float x,y = 0; + float x = 0; + float y = 0; float roll = static_cast (std::rand()) / RAND_MAX * 100; From ff1ecb85c6cc1f02821024e1964abbf81633d545 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 08:22:57 -0800 Subject: [PATCH 0475/1483] Don't bother storing the shape name for the submesh name The submesh name Ogre has is completely useless to us --- 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 1582826b81..826d247c6f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -763,7 +763,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mGroup; size_t mShapeIndex; std::string mMaterialName; - std::string mShapeName; void warn(const std::string &msg) { @@ -872,8 +871,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::VertexDeclaration *decl; int nextBuf = 0; - Ogre::SubMesh *sub = ((mShapeName.length() > 0) ? mesh->createSubMesh(mShapeName) : - mesh->createSubMesh()); + Ogre::SubMesh *sub = mesh->createSubMesh(); // Add vertices sub->useSharedVertices = false; @@ -1061,12 +1059,11 @@ public: if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = dynamic_cast(node); - mShapeName = shape->name; Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(mShapeName.length() > 0) - fullname += "@shape="+mShapeName; + if(shape->name.length() > 0) + fullname += "@shape="+shape->name; Misc::StringUtils::toLower(fullname); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); From 355390429e68b7df609837f1acfbae631cdab5cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 17:27:50 +0100 Subject: [PATCH 0476/1483] Fix World::isUnderwater to use dynamic waterlevel --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 10 +++++----- apps/openmw/mwworld/worldimp.hpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cc23e035e8..eef844c761 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -288,7 +288,7 @@ namespace MWBase virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const = 0; + virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual void togglePOV() = 0; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5dd2b37736..559fc01157 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -381,7 +381,7 @@ void RenderingManager::update (float duration, bool paused) mWater->updateUnderwater( world->isUnderwater( - *world->getPlayer().getPlayer().getCell()->mCell, + world->getPlayer().getPlayer().getCell(), Ogre::Vector3(cam.x, -cam.z, cam.y)) ); mWater->update(duration); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be9..eaee8f5a7b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1411,16 +1411,16 @@ namespace MWWorld const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); if(actor) pos.z += actor->getHalfExtents().z * 1.5; - return isUnderwater(*object.getCell()->mCell, pos); + return isUnderwater(object.getCell(), pos); } bool - World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const + World::isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const { - if (!(cell.mData.mFlags & ESM::Cell::HasWater)) { + if (!(cell->mCell->mData.mFlags & ESM::Cell::HasWater)) { return false; } - return pos.z < cell.mWater; + return pos.z < cell->mWaterLevel; } bool World::isOnGround(const MWWorld::Ptr &ptr) const @@ -1448,7 +1448,7 @@ namespace MWWorld Ogre::Vector3 playerPos(refdata.getPosition().pos); const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(!physactor->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) + if(!physactor->getOnGround() || isUnderwater(currentCell, playerPos)) return 2; if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d347570fe0..0ae81b33a0 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -316,7 +316,7 @@ namespace MWWorld virtual bool isFlying(const MWWorld::Ptr &ptr) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const; + virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { From 8aff033a0cc8bc7921e681b7bc2bf5d2a7b30599 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 18:29:11 +0100 Subject: [PATCH 0477/1483] Atmosphere no longer does "real" alpha blending to blend with the horizon, this is in preparation for proper underwater viewport BG / fog --- apps/openmw/mwrender/sky.cpp | 8 ++++++++ apps/openmw/mwrender/sky.hpp | 1 + files/materials/atmosphere.shader | 3 ++- files/materials/sky.mat | 1 - 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index ed34833e6f..cda9ce6ddc 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -255,6 +255,7 @@ void SkyManager::create() sh::Factory::getInstance().setSharedParameter ("nightFade", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); + sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); @@ -488,6 +489,13 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) weather.mSkyColor.r, weather.mSkyColor.g, weather.mSkyColor.b, weather.mSkyColor.a))); } + if (mFogColour != weather.mFogColor) + { + mFogColour = weather.mFogColor; + sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4( + weather.mFogColor.r, weather.mFogColor.g, weather.mFogColor.b, weather.mFogColor.a))); + } + mCloudSpeed = weather.mCloudSpeed; if (weather.mNight && mStarsOpacity != weather.mNightFade) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 017eb42235..5a12b7ade2 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -211,6 +211,7 @@ namespace MWRender float mStarsOpacity; Ogre::ColourValue mCloudColour; Ogre::ColourValue mSkyColour; + Ogre::ColourValue mFogColour; Ogre::Light* mLightning; diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 5d71d7c32c..eb05c3e18b 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -18,10 +18,11 @@ SH_BEGIN_PROGRAM shInput(float, alphaFade) shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) + shUniform(float4, horizonColour) @shSharedParameter(horizonColour, horizonColour) SH_START_PROGRAM { - shOutputColour(0) = atmosphereColour * float4(1,1,1,alphaFade); + shOutputColour(0) = alphaFade * atmosphereColour + (1.f - alphaFade) * horizonColour; } #endif diff --git a/files/materials/sky.mat b/files/materials/sky.mat index 4af90a170b..e50aa51d8f 100644 --- a/files/materials/sky.mat +++ b/files/materials/sky.mat @@ -59,7 +59,6 @@ material openmw_atmosphere polygon_mode_overrideable off - scene_blend alpha_blend depth_write off } } From 48271e49eccff7379911ae4abcaf00ba39a87125 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 09:57:34 -0800 Subject: [PATCH 0478/1483] Properly update the Ptr object in the mechanics manager when moving across cells --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwmechanics/activators.cpp | 6 ++++-- apps/openmw/mwmechanics/activators.hpp | 4 ++-- apps/openmw/mwmechanics/actors.cpp | 6 ++++-- apps/openmw/mwmechanics/actors.hpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 6 ++++++ apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 10 files changed, 26 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index cb9539ef65..b8733259ff 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -43,7 +43,7 @@ namespace MWBase virtual void remove (const MWWorld::Ptr& ptr) = 0; ///< Deregister an object for management - virtual void updateCell(const MWWorld::Ptr &ptr) = 0; + virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) = 0; ///< Moves an object to a new cell virtual void drop (const MWWorld::CellStore *cellStore) = 0; diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 1a743cad59..b67fcb2164 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -26,13 +26,15 @@ void Activators::removeActivator (const MWWorld::Ptr& ptr) mActivators.erase(iter); } -void Activators::updateActivatorCell(const MWWorld::Ptr &ptr) +void Activators::updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - PtrControllerMap::iterator iter = mActivators.find(ptr); + PtrControllerMap::iterator iter = mActivators.find(old); if(iter != mActivators.end()) { CharacterController ctrl = iter->second; mActivators.erase(iter); + + ctrl.updatePtr(ptr); mActivators.insert(std::make_pair(ptr, ctrl)); } } diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 0b9e984aa6..137674a57a 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -28,8 +28,8 @@ namespace MWMechanics void removeActivator (const MWWorld::Ptr& ptr); ///< Deregister an activator - void updateActivatorCell(const MWWorld::Ptr& ptr); - ///< Updates an activator with a new cell store + void updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an activator with a new Ptr void dropActivators (const MWWorld::CellStore *cellStore); ///< Deregister all activators in the given cell. diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a8c05f17e3..9632bdf769 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -179,13 +179,15 @@ namespace MWMechanics mActors.erase(iter); } - void Actors::updateActorCell(const MWWorld::Ptr &ptr) + void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - PtrControllerMap::iterator iter = mActors.find(ptr); + PtrControllerMap::iterator iter = mActors.find(old); if(iter != mActors.end()) { CharacterController ctrl = iter->second; mActors.erase(iter); + + ctrl.updatePtr(ptr); mActors.insert(std::make_pair(ptr, ctrl)); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index fbd787e835..fc4af8dd63 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -58,8 +58,8 @@ namespace MWMechanics /// /// \note Ignored, if \a ptr is not a registered actor. - void updateActorCell(const MWWorld::Ptr& ptr); - ///< Updates an actor with a new cell store + void updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an actor with a new Ptr void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8f7929805f..ae0114a351 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -131,6 +131,12 @@ CharacterController::~CharacterController() } +void CharacterController::updatePtr(const MWWorld::Ptr &ptr) +{ + mPtr = ptr; +} + + void CharacterController::markerEvent(float time, const std::string &evt) { if(evt == "stop") diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2465aea98f..2b3c50864a 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,6 +79,8 @@ public: CharacterController(const CharacterController &rhs); virtual ~CharacterController(); + void updatePtr(const MWWorld::Ptr &ptr); + Ogre::Vector3 update(float duration); void playGroup(const std::string &groupname, int mode, int count); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index eee72f8805..a02b64e9d3 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -191,12 +191,12 @@ namespace MWMechanics mActivators.removeActivator(ptr); } - void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) + void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.updateActivatorCell(ptr); + mActivators.updateActivator(old, ptr); else - mActors.updateActorCell(ptr); + mActors.updateActor(old, ptr); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 99010b7ffd..5ad8705719 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -48,7 +48,7 @@ namespace MWMechanics virtual void remove (const MWWorld::Ptr& ptr); ///< Deregister an object for management - virtual void updateCell(const MWWorld::Ptr &ptr); + virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr); ///< Moves an object to a new cell virtual void drop(const MWWorld::CellStore *cellStore); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be9..c1725c00c8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -773,7 +773,7 @@ namespace MWWorld mRendering->updateObjectCell(ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->updateCell(copy); + mechMgr->updateCell(ptr, copy); std::string script = MWWorld::Class::get(ptr).getScript(ptr); From 661fd73c6e1668a2c929f4ad5dd07afcaf83ec7a Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 25 Feb 2013 22:00:50 +0400 Subject: [PATCH 0479/1483] fix rotation for objects in inactive cells and forced vanity mode --- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be9..5eaa71b750 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -832,16 +832,16 @@ namespace MWWorld rot.y = Ogre::Degree(y).valueRadians(); rot.z = Ogre::Degree(z).valueRadians(); - float *objRot = ptr.getRefData().getPosition().rot; - if(ptr.getRefData().getBaseNode() == 0 || !mRendering->rotateObject(ptr, rot, adjust)) + if (mRendering->rotateObject(ptr, rot, adjust)) { - objRot[0] = (adjust ? objRot[0] + rot.x : rot.x), objRot[1] = (adjust ? objRot[1] + rot.y : rot.y), objRot[2] = (adjust ? objRot[2] + rot.z : rot.z); - return; - } + // rotate physically iff renderer confirm so + float *objRot = ptr.getRefData().getPosition().rot; + objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; - // do this after rendering rotated the object so it gets changed by Class->adjustRotation - objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; - mPhysics->rotateObject(ptr); + if (ptr.getRefData().getBaseNode() != 0) { + mPhysics->rotateObject(ptr); + } + } } void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) From 5f2c8970014a0c0719be67d9e2453f2323ce2731 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 10:29:48 -0800 Subject: [PATCH 0480/1483] Better handle which collision shapes to load --- components/nifbullet/bullet_nif_loader.cpp | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index a619bdda23..3d9c16ebbf 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -155,6 +155,8 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // the flags we currently use, at least. flags |= node->flags; + isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); + // Marker objects: no collision /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) @@ -191,25 +193,26 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } - if(node->hasBounds) + if(!hasCollisionNode || isCollisionNode) { - cShape->boxTranslation = node->boundPos; - cShape->boxRotation = node->boundRot; - mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); - } + if(node->hasBounds) + { + cShape->boxTranslation = node->boundPos; + cShape->boxRotation = node->boundRot; + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); + } - if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) - { - cShape->mCollide = !(flags&0x800); - handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); + if(node->recType == Nif::RC_NiTriShape) + { + cShape->mCollide = !(flags&0x800); + handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); + } } // For NiNodes, loop through children const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); - const Nif::NodeList &list = ninode->children; for(size_t i = 0;i < list.length();i++) { From 9cd8dd39de31a902eafe118c9e293ee16f87218c Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 21:22:07 +0100 Subject: [PATCH 0481/1483] Make the launcher code conform to the coding standards and cleanup --- apps/launcher/datafilespage.cpp | 8 +++--- apps/launcher/graphicspage.cpp | 29 +++++++++++---------- apps/launcher/maindialog.cpp | 10 +++---- apps/launcher/playpage.cpp | 4 +-- apps/launcher/settings/gamesettings.cpp | 3 ++- apps/launcher/settings/graphicssettings.cpp | 4 +-- apps/launcher/settings/launchersettings.cpp | 4 +-- 7 files changed, 30 insertions(+), 32 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index f8ccf3e83f..dd45c66024 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -1,3 +1,5 @@ +#include "datafilespage.hpp" + #include #include @@ -17,8 +19,6 @@ #include "utils/profilescombobox.hpp" #include "utils/textinputdialog.hpp" -#include "datafilespage.hpp" - using namespace ESM; using namespace std; @@ -216,9 +216,8 @@ void DataFilesPage::setupDataFiles() } QString dataLocal = mGameSettings.getDataLocal(); - if (!dataLocal.isEmpty()) { + if (!dataLocal.isEmpty()) mDataFilesModel->addFiles(dataLocal); - } // Sort by date accessed for now mDataFilesModel->sort(3); @@ -236,7 +235,6 @@ void DataFilesPage::setupDataFiles() if (mProfilesComboBox->findText(QString("Default")) == -1) mProfilesComboBox->addItem(QString("Default")); - if (profile.isEmpty() || profile == QLatin1String("Default")) { mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(QString("Default"))); } else { diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index b5a00b14c5..741aacc9df 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,3 +1,5 @@ +#include "graphicspage.hpp" + #include #include @@ -10,7 +12,6 @@ #include #include "settings/graphicssettings.hpp" -#include "graphicspage.hpp" QString getAspect(int x, int y) { @@ -183,22 +184,22 @@ bool GraphicsPage::setupOgre() void GraphicsPage::loadSettings() { if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) - mVSyncCheckBox->setCheckState(Qt::Checked); + mVSyncCheckBox->setCheckState(Qt::Checked); - if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) - mFullScreenCheckBox->setCheckState(Qt::Checked); + if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) + mFullScreenCheckBox->setCheckState(Qt::Checked); - int aaIndex = mAntiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); - if (aaIndex != -1) - mAntiAliasingComboBox->setCurrentIndex(aaIndex); + int aaIndex = mAntiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); + if (aaIndex != -1) + mAntiAliasingComboBox->setCurrentIndex(aaIndex); - QString resolution = mGraphicsSettings.value(QString("Video/resolution x")); - resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); + QString resolution = mGraphicsSettings.value(QString("Video/resolution x")); + resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); - int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); + int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); - if (resIndex != -1) - mResolutionComboBox->setCurrentIndex(resIndex); + if (resIndex != -1) + mResolutionComboBox->setCurrentIndex(resIndex); } void GraphicsPage::saveSettings() @@ -215,8 +216,8 @@ void GraphicsPage::saveSettings() QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); if (resolutionRe.exactMatch(mResolutionComboBox->currentText().simplified())) { - mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); - mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); + mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); } } diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c91ffa070e..e69f134d29 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,9 +1,10 @@ +#include "maindialog.hpp" + #include #include "utils/checkablemessagebox.hpp" #include "utils/profilescombobox.hpp" -#include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" #include "datafilespage.hpp" @@ -74,9 +75,8 @@ MainDialog::MainDialog() QString config = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/launcher.qss"); file.setFileName(config); - if (!file.exists()) { + if (!file.exists()) file.setFileName(QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("launcher.qss")); - } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox msgBox; @@ -101,9 +101,8 @@ MainDialog::MainDialog() void MainDialog::createIcons() { - if (!QIcon::hasThemeIcon("document-new")) { + if (!QIcon::hasThemeIcon("document-new")) QIcon::setThemeName("tango"); - } // We create a fallback icon because the default fallback doesn't work QIcon graphicsIcon = QIcon(":/icons/tango/video-display.png"); @@ -733,4 +732,3 @@ bool MainDialog::startProgram(const QString &name, const QStringList &arguments, return true; } - diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index 1dbc1b9dfd..b082e2e2ce 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -1,7 +1,7 @@ -#include - #include "playpage.hpp" +#include + PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { QWidget *playWidget = new QWidget(this); diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index af78757b73..56c08582fe 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -1,3 +1,5 @@ +#include "gamesettings.hpp" + #include #include #include @@ -25,7 +27,6 @@ namespace boost } /* namespace boost */ #endif /* (BOOST_VERSION <= 104600) */ -#include "gamesettings.hpp" GameSettings::GameSettings(Files::ConfigurationManager &cfg) : mCfgMgr(cfg) diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp index a92477ebbc..0c55800917 100644 --- a/apps/launcher/settings/graphicssettings.cpp +++ b/apps/launcher/settings/graphicssettings.cpp @@ -1,10 +1,10 @@ +#include "graphicssettings.hpp" + #include #include #include #include -#include "graphicssettings.hpp" - GraphicsSettings::GraphicsSettings() { } diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index 1101a80b95..5d298e814e 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -1,10 +1,10 @@ +#include "launchersettings.hpp" + #include #include #include #include -#include "launchersettings.hpp" - LauncherSettings::LauncherSettings() { } From b209b6a0e6cda392a3b7d78b12ecbdf7aa0838a9 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 22:00:51 +0100 Subject: [PATCH 0482/1483] Added missing includes --- apps/launcher/settings/gamesettings.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index fa62872b06..6c296711f8 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -1,14 +1,13 @@ #ifndef GAMESETTINGS_HPP #define GAMESETTINGS_HPP +#include +#include +#include #include #include -class QTextStream; -class QStringList; -class QString; - namespace Files { typedef std::vector PathContainer; struct ConfigurationManager;} From da575b181e4f6929b97d0255ccc8dec1f8362b6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 13:04:17 -0800 Subject: [PATCH 0483/1483] Use the correct GMST for the race menu --- apps/openmw/mwgui/race.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 699c687ff6..71a4d1b3e4 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -61,7 +61,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu4", "Race")); + setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu5", "Race")); getWidget(mRaceList, "RaceList"); mRaceList->setScrollVisible(true); mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); From 429bc23cf6c2bc763213cb6d1052ee398f374391 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 13:08:40 -0800 Subject: [PATCH 0484/1483] Convert the 0-1 glossiness parameter to 0-255 for shininess --- 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 826d247c6f..fd376045f3 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -683,7 +683,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); instance->setProperty ("specular", sh::makeProperty ( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); + new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); instance->setProperty ("emissive", sh::makeProperty ( new sh::Vector3(emissive.x, emissive.y, emissive.z))); From aefd12dfe046f08ab55160ff4248f8576ca8e406 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 15:44:59 -0800 Subject: [PATCH 0485/1483] Don't create meshes for collision shapes --- components/nifogre/ogre_nif_loader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index fd376045f3..97b297238f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1031,6 +1031,10 @@ public: void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) { + // Do not create meshes for the collision shape (includes all children) + if(node->recType == Nif::RC_RootCollisionNode) + return; + flags |= node->flags; // Marker objects: just skip the entire node From a576e9e430b0feaf5c27bce36a3c3313b831a11a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 16:40:08 -0800 Subject: [PATCH 0486/1483] Set the race selection character preview in a valid (idle) pose. --- apps/openmw/mwrender/characterpreview.cpp | 6 ++++++ apps/openmw/mwrender/characterpreview.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 36cac2155d..c32e9d1d68 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -161,6 +161,7 @@ namespace MWRender void RaceSelectionPreview::update(float angle) { + mAnimation->runAnimation(0.0f); mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); mNode->setVisible (true); @@ -175,4 +176,9 @@ namespace MWRender rebuild(); update(0); } + + void RaceSelectionPreview::onSetup () + { + mAnimation->play("idle", "start", "stop", false); + } } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index d07a03be7d..cf1e250692 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -85,6 +85,8 @@ namespace MWRender public: RaceSelectionPreview(); + virtual void onSetup(); + void update(float angle); const ESM::NPC &getPrototype() const { From 955e2713a949e1d65d3c0f1bbf7975048960c8e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 17:29:32 -0800 Subject: [PATCH 0487/1483] Fix encumbrance term calculation --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 12b40bfdcf..c8c61e118f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -382,7 +382,7 @@ namespace MWClass const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); const float encumbranceTerm = fJumpEncumbranceBase->getFloat() + fJumpEncumbranceMultiplier->getFloat() * - (Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); + (1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); float b = 0.0f; From a5451eb9d92164397a7dd5499976d77bbad436fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 08:30:06 +0100 Subject: [PATCH 0488/1483] Z-up conversion: terrain, objects --- apps/openmw/mwrender/renderingmanager.cpp | 3 +-- apps/openmw/mwrender/terrain.cpp | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 559fc01157..455e84f5ef 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -147,8 +147,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Morrowind uses, and it automagically makes everything work as it // should. SceneNode *rt = mRendering.getScene()->getRootSceneNode(); - mMwRoot = rt->createChildSceneNode("mwRoot"); - mMwRoot->pitch(Degree(-90)); + mMwRoot = rt; mObjects.setMwRoot(mMwRoot); mActors.setMwRoot(mMwRoot); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 2c2e9e6fcf..47ee6f06f9 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -26,7 +26,7 @@ namespace MWRender //---------------------------------------------------------------------------------------------- TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend) : - mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) + mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Y, mLandSize, mWorldSize)), mRendering(rend) { mTerrainGlobals = OGRE_NEW TerrainGlobalOptions(); @@ -54,8 +54,8 @@ namespace MWRender mTerrainGlobals->setCompositeMapDistance(mWorldSize*2); mTerrainGroup.setOrigin(Vector3(mWorldSize/2, - 0, - -mWorldSize/2)); + mWorldSize/2, + 0)); Terrain::ImportData& importSettings = mTerrainGroup.getDefaultImportSettings(); From 3cb3ec91c065cd7ce4c229476b0e95a12cfe41f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 09:12:35 +0100 Subject: [PATCH 0489/1483] Z-up conversion: camera --- apps/openmw/mwrender/player.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 9ab8a7de33..1ac3b072f5 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -113,11 +113,6 @@ namespace MWRender Ogre::Vector3 dir = mCamera->getRealDirection(); Ogre::Vector3 up = mCamera->getRealUp(); - Ogre::Real xch; - xch = pos.y, pos.y = -pos.z, pos.z = xch; - xch = dir.y, dir.y = -dir.z, dir.z = xch; - xch = up.y, up.y = -up.z, up.z = xch; - MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir, up); } @@ -323,10 +318,8 @@ namespace MWRender bool Player::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera) { - float xch; mCamera->getParentSceneNode ()->needUpdate(true); camera = mCamera->getRealPosition(); - xch = camera.z, camera.z = camera.y, camera.y = -xch; player = mPlayerNode->getPosition(); return mFirstPersonView && !mVanity.enabled && !mPreviewMode; From 3ef952172d5a05133d94b9f3e6cf65a636eafa26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 10:38:48 +0100 Subject: [PATCH 0490/1483] Z-up conversion: water, sky --- apps/openmw/mwrender/renderingmanager.cpp | 7 +++--- apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwrender/water.cpp | 14 +++++------ files/materials/objects.shader | 12 ++++----- files/materials/terrain.shader | 16 ++++++------ files/materials/underwater.h | 6 ++--- files/materials/water.shader | 30 ++++++++++++----------- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 455e84f5ef..b2d7fbff08 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -365,7 +365,7 @@ void RenderingManager::update (float duration, bool paused) float *fpos = data.getPosition().pos; // only for LocalMap::updatePlayer() - Ogre::Vector3 pos(fpos[0], -fpos[2], -fpos[1]); + Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); Ogre::SceneNode *node = data.getBaseNode(); Ogre::Quaternion orient = @@ -381,7 +381,7 @@ void RenderingManager::update (float duration, bool paused) mWater->updateUnderwater( world->isUnderwater( world->getPlayer().getPlayer().getCell(), - Ogre::Vector3(cam.x, -cam.z, cam.y)) + cam) ); mWater->update(duration); } @@ -613,8 +613,7 @@ void RenderingManager::sunDisable() void RenderingManager::setSunDirection(const Ogre::Vector3& direction) { // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), - // then convert from MW to ogre coordinates (swap y,z and make y negative) - if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y)); + if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); mSkyManager->setSunDirection(direction); } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 767f3c4639..b747b0d9a8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -236,7 +236,6 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) { mSceneMgr = pMwRoot->getCreator(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates mRootNode->setInheritOrientation(false); } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e8f099640b..e8ccbb2b46 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -42,9 +42,9 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mIsUnderwater = false; - mWaterPlane = Plane(Vector3::UNIT_Y, 0); + mWaterPlane = Plane(Vector3::UNIT_Z, 0); - MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z); + MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Y); mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); @@ -168,12 +168,12 @@ void Water::setHeight(const float height) { mTop = height; - mWaterPlane = Plane(Vector3::UNIT_Y, height); + mWaterPlane = Plane(Vector3::UNIT_Z, height); // small error due to reflection texture size & reflection distortion - mErrorPlane = Plane(Vector3::UNIT_Y, height - 5); + mErrorPlane = Plane(Vector3::UNIT_Z, height - 5); - mWaterNode->setPosition(0, height, 0); + mWaterNode->setPosition(0, 0, height); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); } @@ -199,7 +199,7 @@ Water::updateUnderwater(bool underwater) Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) { - return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); + return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), gridY * CELL_SIZE + (CELL_SIZE / 2), mTop); } void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) @@ -216,7 +216,7 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) mReflectionRenderActive = true; Vector3 pos = mCamera->getRealPosition(); - pos.y = mTop*2 - pos.y; + pos.z = mTop*2 - pos.z; mSky->setSkyPosition(pos); mReflectionCamera->enableReflection(mWaterPlane); } diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 25624351c8..6adf7e3fa0 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -225,9 +225,9 @@ float3 waterEyePos = float3(1,1,1); // NOTE: this calculation would be wrong for non-uniform scaling float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); + waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.y >= waterLevel || waterEnabled != 1.f) + if (worldPos.z >= waterLevel || waterEnabled != 1.f) caustics = float3(1,1,1); #endif @@ -269,7 +269,7 @@ #if UNDERWATER // regular fog only if fragment is above water - if (worldPos.y > waterLevel || waterEnabled != 1.f) + if (worldPos.z > waterLevel || waterEnabled != 1.f) #endif shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif @@ -278,7 +278,7 @@ shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); #if UNDERWATER - float fogAmount = (cameraPos.y > waterLevel) + float fogAmount = (cameraPos.z > waterLevel) ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); @@ -292,14 +292,14 @@ waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); float3 watercolour = ( gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; + watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; float darkness = VISIBILITY*2.0; darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; - float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; + float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index dee7332630..e4f1cf091a 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -88,8 +88,8 @@ float toMorph = -min(0, sign(uv1.y - lodMorph.y)); // morph - // this assumes XZ terrain alignment - worldPos.y += uv1.x * toMorph * lodMorph.x; + // this assumes XY terrain alignment + worldPos.z += uv1.x * toMorph * lodMorph.x; shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); @@ -233,9 +233,9 @@ float3 waterEyePos = float3(1,1,1); // NOTE: this calculation would be wrong for non-uniform scaling float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); + waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.y >= waterLevel) + if (worldPos.z >= waterLevel) caustics = float3(1,1,1); @@ -341,7 +341,7 @@ #if UNDERWATER // regular fog only if fragment is above water - if (worldPos.y > waterLevel) + if (worldPos.z > waterLevel) #endif shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif @@ -350,7 +350,7 @@ shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); #if UNDERWATER - float fogAmount = (cameraPos.y > waterLevel) + float fogAmount = (cameraPos.z > waterLevel) ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); @@ -365,14 +365,14 @@ float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; + watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; float darkness = VISIBILITY*2.0; darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; - float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; + float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); #endif diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 18052a98da..3b25404086 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -79,9 +79,9 @@ float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed) { - float waterDepth = shSaturate((waterEyePos.y - worldPos.y) / 50.0); + float waterDepth = shSaturate((waterEyePos.y - worldPos.z) / 50.0); - float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,1,0), waterLevel); + float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,0,1), waterLevel); ///\ todo clean this up float causticdepth = length(causticPos-worldPos.xyz); @@ -91,7 +91,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xzy * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); diff --git a/files/materials/water.shader b/files/materials/water.shader index 6bd277eab6..b7fb60b6b7 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -122,7 +122,7 @@ #define REFL_BUMP 0.08 // reflection distortion amount #define REFR_BUMP 0.06 // refraction distortion amount - #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering + #define SCATTER_AMOUNT 1.0 // amount of sunlight scattering #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering #define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction @@ -219,25 +219,27 @@ float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xzy; + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xyz; - normal = normalize(float3(normal.x * BUMP, normal.y, normal.z * BUMP)); + normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); + normal = float3(normal.x, normal.y, -normal.z); // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xzy; - lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y, lNormal.z * BUMP)); - + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; + lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); + lNormal = float3(lNormal.x, lNormal.y, -lNormal.z); + float3 lVec = normalize(sunPosition.xyz); float3 vVec = normalize(position.xyz - cameraPos.xyz); - float isUnderwater = (cameraPos.y > 0) ? 0.0 : 1.0; + float isUnderwater = (cameraPos.z > 0) ? 0.0 : 1.0; // sunlight scattering - float3 pNormal = float3(0,1,0); + float3 pNormal = float3(0,0,1); float3 lR = reflect(lVec, lNormal); float3 llR = reflect(lVec, pNormal); @@ -246,13 +248,13 @@ float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*gammaCorrectRead(float3(1.0,0.4,0.0)), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); // fresnel - float ior = (cameraPos.y>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float ior = (cameraPos.z>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air float fresnel = fresnel_dielectric(-vVec, normal, ior); fresnel = shSaturate(fresnel); // reflection - float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb); + float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb); // refraction float3 R = reflect(vVec, normal); @@ -260,13 +262,13 @@ // check the depth at the refracted coords, and don't do any normal distortion for the refraction if the object to refract // is actually above the water (objectDepth < waterDepth) // this solves silhouettes around objects above the water - float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xz*REFR_BUMP)).x * far - depthPassthrough; + float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xy*REFR_BUMP)).x * far - depthPassthrough; float doRefraction = (refractDepth < 0) ? 0.f : 1.f; - float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(shoreFade * normal.xz*REFR_BUMP * doRefraction))*1.0).rgb); + float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(shoreFade * normal.xy*REFR_BUMP * doRefraction))*1.0).rgb); // brighten up the refraction underwater - refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction; + refraction = (cameraPos.z < 0) ? shSaturate(refraction * 1.5) : refraction; // specular float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); @@ -290,7 +292,7 @@ watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); float darkness = VISIBILITY*2.0; - darkness = clamp((cameraPos.y+darkness)/darkness,0.2,1.0); + darkness = clamp((cameraPos.z+darkness)/darkness,0.2,1.0); float fog = shSaturate(length(cameraPos.xyz-position.xyz) / VISIBILITY); From 5c0c5854e893b0aaa44ab3e936b0af24f9026cfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 12:01:10 +0100 Subject: [PATCH 0491/1483] Unrelated change: we always want the XAutoRepeat workaround, regardless of using exclusive input or not --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4a79f77b85..f7e1c8a845 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -87,10 +87,12 @@ namespace MWInput std::string("false"))); pl.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false"))); - pl.insert(std::make_pair(std::string("XAutoRepeatOn"), - std::string("true"))); #endif } +#if defined OIS_LINUX_PLATFORM + pl.insert(std::make_pair(std::string("XAutoRepeatOn"), + std::string("true"))); +#endif #if defined(__APPLE__) && !defined(__LP64__) // Give the application window focus to receive input events From 2e7bc1a368c730d7fc3e3691037c69476c0b5d0e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:39:10 +0100 Subject: [PATCH 0492/1483] Z-up conversion: local map, fix tcg --- apps/openmw/mwgui/map_window.cpp | 6 +- apps/openmw/mwrender/localmap.cpp | 80 +++++++++++------------ apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/sky.cpp | 3 +- apps/openmw/mwworld/worldimp.cpp | 4 +- files/materials/water.shader | 4 +- libs/openengine/bullet/physic.cpp | 1 - 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 4e2ee517ea..bbb2be648b 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -88,7 +88,7 @@ void LocalMapBase::applyFogOfWar() + boost::lexical_cast(my); std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (mInterior ? (my-1) : -1*(my-1))); + + boost::lexical_cast(mCurY + (-1*(my-1))); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" @@ -127,7 +127,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) { // map std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); + + boost::lexical_cast(y + (-1*(my-1))); std::string name = "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my); @@ -173,7 +173,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) } else { - Ogre::Vector2 position (marker.x, -marker.y); + Ogre::Vector2 position (marker.x, marker.y); MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d878cb86ed..b661c0795b 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -28,9 +28,6 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mCellCamera = mRendering->getScene()->createCamera("CellCamera"); mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); - // look down -y - const float sqrt0pt5 = 0.707106781; - mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0)); mCameraNode->attachObject(mCellCamera); } @@ -82,8 +79,8 @@ void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell) } else { - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; // divide into segments @@ -107,6 +104,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) mInterior = false; mCameraRotNode->setOrientation(Quaternion::IDENTITY); + mCellCamera->setOrientation(Quaternion(Ogre::Math::Cos(Ogre::Degree(0)/2.f), 0, 0, -Ogre::Math::Sin(Ogre::Degree(0)/2.f))); int x = cell->mCell->getGridX(); int y = cell->mCell->getGridY(); @@ -115,7 +113,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) mCameraPosNode->setPosition(Vector3(0,0,0)); - render((x+0.5)*sSize, (-y-0.5)*sSize, -10000, 10000, sSize, sSize, name); + render((x+0.5)*sSize, (y+0.5)*sSize, -10000, 10000, sSize, sSize, name); } void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, @@ -124,40 +122,44 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mInterior = true; mBounds = bounds; - Vector2 z(mBounds.getMaximum().y, mBounds.getMinimum().y); + float zMin = mBounds.getMinimum().z; + float zMax = mBounds.getMaximum().z; const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); - Radian angle(std::atan2(-north.x, -north.y)); + Radian angle = Ogre::Math::ATan2 (north.x, north.y); mAngle = angle.valueRadians(); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, Math::Sin(angle/2.f), 0)); + + mCellCamera->setOrientation(Quaternion::IDENTITY); + mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, 0, -Math::Sin(angle/2.f))); // rotate the cell and merge the rotated corners to the bounding box - Vector2 _center(bounds.getCenter().x, bounds.getCenter().z); - Vector3 _c1 = bounds.getCorner(AxisAlignedBox::NEAR_LEFT_BOTTOM); - Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); - Vector3 _c3 = bounds.getCorner(AxisAlignedBox::NEAR_RIGHT_BOTTOM); - Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); - Vector2 c1(_c1.x, _c1.z); - Vector2 c2(_c2.x, _c2.z); - Vector2 c3(_c3.x, _c3.z); - Vector2 c4(_c4.x, _c4.z); + Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); + Vector3 _c1 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); + Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); + Vector3 _c3 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_TOP); + Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_TOP); + + Vector2 c1(_c1.x, _c1.y); + Vector2 c2(_c2.x, _c2.y); + Vector2 c3(_c3.x, _c3.y); + Vector2 c4(_c4.x, _c4.y); c1 = rotatePoint(c1, _center, mAngle); c2 = rotatePoint(c2, _center, mAngle); c3 = rotatePoint(c3, _center, mAngle); c4 = rotatePoint(c4, _center, mAngle); - mBounds.merge(Vector3(c1.x, 0, c1.y)); - mBounds.merge(Vector3(c2.x, 0, c2.y)); - mBounds.merge(Vector3(c3.x, 0, c3.y)); - mBounds.merge(Vector3(c4.x, 0, c4.y)); + mBounds.merge(Vector3(c1.x, c1.y, 0)); + mBounds.merge(Vector3(c2.x, c2.y, 0)); + mBounds.merge(Vector3(c3.x, c3.y, 0)); + mBounds.merge(Vector3(c4.x, c4.y, 0)); - Vector2 center(mBounds.getCenter().x, mBounds.getCenter().z); + Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - mCameraPosNode->setPosition(Vector3(center.x, 0, center.y)); + mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); // divide into segments const int segsX = std::ceil( length.x / sSize ); @@ -172,7 +174,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, Vector2 start = min + Vector2(sSize*x,sSize*y); Vector2 newcenter = start + 4096; - render(newcenter.x - center.x, newcenter.y - center.y, z.y, z.x, sSize, sSize, + render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize, cell->mCell->mName + "_" + coordStr(x,y)); } } @@ -193,7 +195,7 @@ void LocalMap::render(const float x, const float y, mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); mRenderingManager->disableLights(); - mCameraNode->setPosition(Vector3(x, zhigh+100000, y)); + mCameraNode->setPosition(Vector3(x, y, 100000)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite @@ -272,15 +274,15 @@ void LocalMap::render(const float x, const float y, void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) { - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle); + pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), mAngle); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); x = std::ceil((pos.x - min.x)/sSize)-1; y = std::ceil((pos.y - min.y)/sSize)-1; nX = (pos.x - min.x - sSize*x)/sSize; - nY = (pos.y - min.y - sSize*y)/sSize; + nY = 1.0-(pos.y - min.y - sSize*y)/sSize; } bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) @@ -311,19 +313,19 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni int x,y; float u,v; - Vector2 pos(position.x, position.z); + Vector2 pos(position.x, position.y); if (mInterior) getInteriorMapPosition(pos, u,v, x,y); - Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).zAxis(); + Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); if (!mInterior) { x = std::ceil(pos.x / sSize)-1; - y = std::ceil(-pos.y / sSize)-1; + y = std::ceil(pos.y / sSize)-1; mCellX = x; mCellY = y; } @@ -337,7 +339,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { u = std::abs((pos.x - (sSize*x))/sSize); - v = 1-std::abs((pos.y + (sSize*y))/sSize); + v = 1.0-std::abs((pos.y - (sSize*y))/sSize); texBaseName = "Cell_"; } else @@ -346,15 +348,13 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } MWBase::Environment::get().getWindowManager()->setPlayerPos(u, v); - MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, -playerdirection.z); + MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); // explore radius (squared) const float sqrExploreRadius = (mInterior ? 0.01 : 0.09) * sFogOfWarResolution*sFogOfWarResolution; const float exploreRadius = (mInterior ? 0.1 : 0.3) * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) - int intExtMult = mInterior ? 1 : -1; // interior and exterior have reversed Y coordinates (interior: top to bottom) - // change the affected fog of war textures (in a 3x3 grid around the player) for (int mx = -1; mx<2; ++mx) { @@ -375,7 +375,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!affected) continue; - std::string texName = texBaseName + coordStr(x+mx,y+my*intExtMult); + std::string texName = texBaseName + coordStr(x+mx,y+my*-1); TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog"); if (!tex.isNull()) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b2d7fbff08..fe8c5f57fb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -368,8 +368,10 @@ void RenderingManager::update (float duration, bool paused) Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); Ogre::SceneNode *node = data.getBaseNode(); + //Ogre::Quaternion orient = + //node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); Ogre::Quaternion orient = - node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); +node->_getDerivedOrientation(); mLocalMap->updatePlayer(pos, orient); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index b747b0d9a8..87790fab5f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -110,7 +110,7 @@ void BillboardObject::setPosition(const Vector3& pPosition) Vector3 BillboardObject::getPosition() const { Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition(); - return Vector3(p.x, -p.z, p.y); + return p; } void BillboardObject::setVisibilityFlags(int flags) @@ -390,7 +390,6 @@ void SkyManager::update(float duration) // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun Vector3 sun = mSunGlare->getPosition(); - sun = Vector3(sun.x, sun.z, -sun.y); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index eaee8f5a7b..ce39842b31 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1228,8 +1228,8 @@ namespace MWWorld if (!ref) return Vector2(0, 1); Ogre::SceneNode* node = ref->mData.getBaseNode(); - Vector3 dir = node->_getDerivedOrientation().yAxis(); - Vector2 d = Vector2(dir.x, dir.z); + Vector3 dir = node->_getDerivedOrientation() * Ogre::Vector3(0,1,0); + Vector2 d = Vector2(dir.x, dir.y); return d; } diff --git a/files/materials/water.shader b/files/materials/water.shader index b7fb60b6b7..a58a9c38b9 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -122,7 +122,7 @@ #define REFL_BUMP 0.08 // reflection distortion amount #define REFR_BUMP 0.06 // refraction distortion amount - #define SCATTER_AMOUNT 1.0 // amount of sunlight scattering + #define SCATTER_AMOUNT 0.3 // amount of sunlight scattering #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering #define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction @@ -223,7 +223,7 @@ normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = float3(normal.x, normal.y, -normal.z); - + // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 5d5749d5d8..f993ce68e2 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -193,7 +193,6 @@ namespace Physic if(!isDebugCreated) { Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - node->pitch(Ogre::Degree(-90)); mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld); dynamicsWorld->setDebugDrawer(mDebugDrawer); isDebugCreated = true; From 284ba58e1e7372d74c80acd0f3f18d0b728ea901 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:52:01 +0100 Subject: [PATCH 0493/1483] Z-up conversion: global map, shader fix --- apps/openmw/mwgui/map_window.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 2 +- files/materials/objects.shader | 2 +- files/materials/terrain.shader | 2 +- files/materials/underwater.h | 11 ++++++----- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index bbb2be648b..34f246d8b1 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -397,7 +397,7 @@ void MapWindow::globalMapUpdatePlayer () Ogre::Vector2 dir (orient.yAxis ().x, -orient.yAxis().z); float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.z, worldX, worldY); + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); worldX *= mGlobalMapRender->getWidth(); worldY *= mGlobalMapRender->getHeight(); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 072015f9a8..055faaa1f7 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -190,7 +190,7 @@ namespace MWRender { imageX = float(x / 8192.f - mMinX) / (mMaxX - mMinX + 1); - imageY = 1.f-float(-z / 8192.f - mMinY) / (mMaxY - mMinY + 1); + imageY = 1.f-float(z / 8192.f - mMinY) / (mMaxY - mMinY + 1); } void GlobalMap::cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 6adf7e3fa0..0f1b3722fa 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -296,7 +296,7 @@ float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); + darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index e4f1cf091a..d8bc00c187 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -369,7 +369,7 @@ float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); + darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 3b25404086..a760202fa2 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -79,7 +79,7 @@ float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed) { - float waterDepth = shSaturate((waterEyePos.y - worldPos.z) / 50.0); + float waterDepth = shSaturate((waterEyePos.z - worldPos.z) / 50.0); float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,0,1), waterLevel); @@ -91,20 +91,21 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); float NdotL = max(dot(worldNormal.xyz, lightDirectionWS0.xyz),0.0); - float causticR = 1.0-perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticR = 1.0-perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; /// \todo sunFade // float3 caustics = clamp(pow(float3(causticR)*5.5,float3(5.5*causticdepth)),0.0,1.0)*NdotL*sunFade*causticdepth; float3 caustics = clamp(pow(float3(causticR,causticR,causticR)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)),0.0,1.0)*NdotL*causticdepth; - float causticG = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; - float causticB = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticG = 1.0-perturb(causticMap,causticPos.xy+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticB = 1.0-perturb(causticMap,causticPos.xy+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; From 341f9b96e2a589a86977d42b1856d147b4bc6f80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:53:23 +0100 Subject: [PATCH 0494/1483] Local map: restore zHigh --- apps/openmw/mwrender/localmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b661c0795b..601ee58e31 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -195,7 +195,7 @@ void LocalMap::render(const float x, const float y, mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); mRenderingManager->disableLights(); - mCameraNode->setPosition(Vector3(x, y, 100000)); + mCameraNode->setPosition(Vector3(x, y, zhigh+100000)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite From cc9b72b9b1f75f138bb38e1b095ed84a2b2f71a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:01:10 +0100 Subject: [PATCH 0495/1483] Removing some leftovers of mwRoot node --- apps/openmw/mwrender/actors.cpp | 8 ++++---- apps/openmw/mwrender/actors.hpp | 4 ++-- apps/openmw/mwrender/debugging.cpp | 8 ++++---- apps/openmw/mwrender/debugging.hpp | 4 ++-- apps/openmw/mwrender/objects.cpp | 20 ++++++++++---------- apps/openmw/mwrender/objects.hpp | 4 ++-- apps/openmw/mwrender/renderingmanager.cpp | 19 +++++++------------ apps/openmw/mwrender/renderingmanager.hpp | 5 +---- apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwrender/sky.hpp | 2 +- 10 files changed, 35 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 78521d0ce6..83c07737ce 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -28,8 +28,8 @@ Actors::~Actors() } } -void Actors::setMwRoot(Ogre::SceneNode* root) -{ mMwRoot = root; } +void Actors::setRootNode(Ogre::SceneNode* root) +{ mRootNode = root; } void Actors::insertBegin(const MWWorld::Ptr &ptr) { @@ -40,7 +40,7 @@ void Actors::insertBegin(const MWWorld::Ptr &ptr) else { //Create the scenenode and put it in the map - cellnode = mMwRoot->createChildSceneNode(); + cellnode = mRootNode->createChildSceneNode(); mCellSceneNodes[ptr.getCell()] = cellnode; } @@ -159,7 +159,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) node = celliter->second; else { - node = mMwRoot->createChildSceneNode(); + node = mRootNode->createChildSceneNode(); mCellSceneNodes[newCell] = node; } node->addChild(cur.getRefData().getBaseNode()); diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index c89bfbaf5e..75a18ba915 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -20,7 +20,7 @@ namespace MWRender typedef std::map PtrAnimationMap; OEngine::Render::OgreRenderer &mRend; - Ogre::SceneNode* mMwRoot; + Ogre::SceneNode* mRootNode; CellSceneNodeMap mCellSceneNodes; PtrAnimationMap mAllActors; @@ -29,7 +29,7 @@ namespace MWRender Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); - void setMwRoot(Ogre::SceneNode* root); + void setRootNode(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); void insertCreature (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 2061b74d7f..54f288bff8 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -150,9 +150,9 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) return result; } -Debugging::Debugging(SceneNode *mwRoot, OEngine::Physic::PhysicEngine *engine) : - mMwRoot(mwRoot), mEngine(engine), - mSceneMgr(mwRoot->getCreator()), +Debugging::Debugging(SceneNode *root, OEngine::Physic::PhysicEngine *engine) : + mRootNode(root), mEngine(engine), + mSceneMgr(root->getCreator()), mPathgridEnabled(false), mInteriorPathgridNode(NULL), mPathGridRoot(NULL), mGridMatsCreated(false) @@ -208,7 +208,7 @@ void Debugging::togglePathgrid() createGridMaterials(); // add path grid meshes to already loaded cells - mPathGridRoot = mMwRoot->createChildSceneNode(); + mPathGridRoot = mRootNode->createChildSceneNode(); for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) { enableCellPathgrid(*it); diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index 07e5f0a3f4..6a4eef58f4 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -54,7 +54,7 @@ namespace MWRender typedef std::vector CellList; CellList mActiveCells; - Ogre::SceneNode *mMwRoot; + Ogre::SceneNode *mRootNode; Ogre::SceneNode *mPathGridRoot; @@ -78,7 +78,7 @@ namespace MWRender Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid); Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid); public: - Debugging(Ogre::SceneNode* mwRoot, OEngine::Physic::PhysicEngine *engine); + Debugging(Ogre::SceneNode* root, OEngine::Physic::PhysicEngine *engine); ~Debugging(); bool toggleRenderMode (int mode); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 76f38eefc2..add781459e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -57,14 +57,14 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) } } -void Objects::setMwRoot(Ogre::SceneNode* root) +void Objects::setRootNode(Ogre::SceneNode* root) { - mMwRoot = root; + mRootNode = root; } void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) { - Ogre::SceneNode* root = mMwRoot; + Ogre::SceneNode* root = mRootNode; Ogre::SceneNode* cellnode; if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) { @@ -390,9 +390,9 @@ void Objects::enableLights() std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(it->name)->setVisible(true); + mRootNode->getCreator()->getLight(it->name)->setVisible(true); ++it; } else @@ -405,9 +405,9 @@ void Objects::disableLights() std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(it->name)->setVisible(false); + mRootNode->getCreator()->getLight(it->name)->setVisible(false); ++it; } else @@ -460,9 +460,9 @@ void Objects::update(const float dt) std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); + Ogre::Light* light = mRootNode->getCreator()->getLight(it->name); float brightness; float cycle_time; @@ -550,7 +550,7 @@ void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) MWWorld::CellStore *newCell = cur.getCell(); if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { - node = mMwRoot->createChildSceneNode(); + node = mRootNode->createChildSceneNode(); mCellSceneNodes[newCell] = node; } else { node = mCellSceneNodes[newCell]; diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 5801014642..73e95a3c53 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -53,7 +53,7 @@ class Objects{ std::map mStaticGeometrySmall; std::map mBounds; std::vector mLights; - Ogre::SceneNode* mMwRoot; + Ogre::SceneNode* mRootNode; bool mIsStatic; static int uniqueID; @@ -90,7 +90,7 @@ public: void removeCell(MWWorld::CellStore* store); void buildStaticGeometry(MWWorld::CellStore &cell); - void setMwRoot(Ogre::SceneNode* root); + void setRootNode(Ogre::SceneNode* root); void rebuildStaticGeometry(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fe8c5f57fb..fe3dc776d1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -141,25 +141,20 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const applyCompositors(); - // Turn the entire scene (represented by the 'root' node) -90 - // degrees around the x axis. This makes Z go upwards, and Y go into - // the screen (when x is to the right.) This is the orientation that - // Morrowind uses, and it automagically makes everything work as it - // should. SceneNode *rt = mRendering.getScene()->getRootSceneNode(); - mMwRoot = rt; + mRootNode = rt; - mObjects.setMwRoot(mMwRoot); - mActors.setMwRoot(mMwRoot); + mObjects.setRootNode(mRootNode); + mActors.setRootNode(mRootNode); - Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player"); + Ogre::SceneNode *playerNode = mRootNode->createChildSceneNode ("player"); mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mShadows = new Shadows(&mRendering); mTerrainManager = new TerrainManager(mRendering.getScene(), this); - mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera()); + mSkyManager = new SkyManager(mRootNode, mRendering.getCamera()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); @@ -168,7 +163,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mSun = 0; - mDebugging = new Debugging(mMwRoot, engine); + mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); @@ -321,7 +316,7 @@ void RenderingManager::update (float duration, bool paused) Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { - orig.z += mPlayer->getHeight() * mMwRoot->getScale().z; + orig.z += mPlayer->getHeight() * mRootNode->getScale().z; btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index bdb5447e32..53c63cfedd 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -228,10 +228,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::ColourValue mAmbientColor; Ogre::Light* mSun; - /// Root node for all objects added to the scene. This is rotated so - /// that the OGRE coordinate system matches that used internally in - /// Morrowind. - Ogre::SceneNode *mMwRoot; + Ogre::SceneNode *mRootNode; OEngine::Physic::PhysicEngine* mPhysicsEngine; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 87790fab5f..0620796931 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -203,7 +203,7 @@ unsigned int Moon::getPhaseInt() const return 0; } -SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) +SkyManager::SkyManager (SceneNode* root, Camera* pCamera) : mHour(0.0f) , mDay(0) , mMonth(0) @@ -234,7 +234,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) , mCloudAnimationTimer(0.f) , mMoonRed(false) { - mSceneMgr = pMwRoot->getCreator(); + mSceneMgr = root->getCreator(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); mRootNode->setInheritOrientation(false); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 52fd7b4aa8..feaba3d969 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -112,7 +112,7 @@ namespace MWRender class SkyManager { public: - SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera); + SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera); ~SkyManager(); void update(float duration); From cd68012498881544eb00b9f902ab3bc9ef1bd1e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:28:35 +0100 Subject: [PATCH 0496/1483] Z-up conversion: raycasts --- apps/openmw/mwworld/physicssystem.cpp | 14 ++++++-------- apps/openmw/mwworld/worldimp.cpp | 11 +++++------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 0c1f580488..65cbc1164e 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -264,9 +264,8 @@ namespace MWWorld Ogre::Vector3 to = ray.getPoint(queryDistance); btVector3 _from, _to; - // OGRE to MW coordinates - _from = btVector3(from.x, -from.z, from.y); - _to = btVector3(to.x, -to.z, to.y); + _from = btVector3(from.x, from.y, from.z); + _to = btVector3(to.x, to.y, to.z); std::vector < std::pair > results; /* auto */ results = mEngine->rayTest2(_from,_to); @@ -287,7 +286,7 @@ namespace MWWorld Ray centerRay = mRender.getCamera()->getCameraToViewportRay( mRender.getViewport()->getWidth()/2, mRender.getViewport()->getHeight()/2); - btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); + btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z); return result; } @@ -295,7 +294,7 @@ namespace MWWorld { //get a ray pointing to the center of the viewport Ray centerRay = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); - btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); + btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z); return result; } @@ -335,9 +334,8 @@ namespace MWWorld Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable btVector3 _from, _to; - // OGRE to MW coordinates - _from = btVector3(from.x, -from.z, from.y); - _to = btVector3(to.x, -to.z, to.y); + _from = btVector3(from.x, from.y, from.z); + _to = btVector3(to.x, to.y, to.z); std::pair result = mEngine->rayTest(_from, _to); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ce39842b31..24a1f83022 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1024,7 +1024,6 @@ namespace MWWorld // currently its here because we need to access the physics system float* p = mPlayer->getPlayer().getRefData().getPosition().pos; Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); - sun = Vector3(sun.x, -sun.z, sun.y); mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } @@ -1122,7 +1121,7 @@ namespace MWWorld } else p = mPhysics->getRayPoint(results.front().first); - Ogre::Vector3 pos(p.x(), p.z(), -p.y()); + Ogre::Vector3 pos(p.x(), p.y(), p.z()); Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; @@ -1150,7 +1149,7 @@ namespace MWWorld } else p = mPhysics->getRayPoint(results.at (1).first); - Ogre::Vector3 pos(p.x(), p.z(), -p.y()); + Ogre::Vector3 pos(p.x(), p.y(), p.z()); Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); @@ -1299,7 +1298,7 @@ namespace MWWorld if (isCellExterior()) { int cellX, cellY; - positionToIndex(result.second[0], -result.second[2], cellX, cellY); + positionToIndex(result.second[0], result.second[1], cellX, cellY); cell = mCells.getExterior(cellX, cellY); } else @@ -1307,8 +1306,8 @@ namespace MWWorld ESM::Position pos = getPlayer().getPlayer().getRefData().getPosition(); pos.pos[0] = result.second[0]; - pos.pos[1] = -result.second[2]; - pos.pos[2] = result.second[1]; + pos.pos[1] = result.second[1]; + pos.pos[2] = result.second[2]; Ptr dropped = copyObjectToCell(object, *cell, pos); PCDropped(dropped); From b9912a19e0ed585b041c33ce2861b224dea23369 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:31:30 +0100 Subject: [PATCH 0497/1483] Z-up conversion: fix player arrow direction on global map --- apps/openmw/mwgui/map_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 34f246d8b1..6f7f0eaabc 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -394,7 +394,7 @@ void MapWindow::globalMapUpdatePlayer () { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, -orient.yAxis().z); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); float worldX, worldY; mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); From a7102c143f2f44701c95e2824ab93a459bb5d162 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Feb 2013 14:33:05 +0100 Subject: [PATCH 0498/1483] ESX variable type cleanup --- apps/openmw/mwworld/globals.cpp | 66 ++++++++++++++++----------------- components/esm/defs.hpp | 4 +- components/esm/loadglob.cpp | 4 +- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index f010661b9d..8742dd8927 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -21,21 +21,21 @@ namespace MWWorld Globals::Collection::const_iterator Globals::find (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); - - return iter; + + return iter; } Globals::Collection::iterator Globals::find (const std::string& name) { Collection::iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); - - return iter; + + return iter; } Globals::Globals (const MWWorld::ESMStore& store) @@ -46,44 +46,44 @@ namespace MWWorld { char type = ' '; Data value; - + switch (iter->mType) { case ESM::VT_Short: - + type = 's'; value.mShort = *reinterpret_cast ( &iter->mValue); break; - - case ESM::VT_Int: - + + case ESM::VT_Long: + type = 'l'; value.mLong = *reinterpret_cast ( &iter->mValue); break; - + case ESM::VT_Float: - + type = 'f'; value.mFloat = *reinterpret_cast ( &iter->mValue); break; - + default: - + throw std::runtime_error ("unsupported global variable type"); - } + } mVariables.insert (std::make_pair (iter->mId, std::make_pair (type, value))); } - + if (mVariables.find ("dayspassed")==mVariables.end()) { // vanilla Morrowind does not define dayspassed. Data value; value.mLong = 0; - + mVariables.insert (std::make_pair ("dayspassed", std::make_pair ('l', value))); } } @@ -91,31 +91,31 @@ namespace MWWorld const Globals::Data& Globals::operator[] (const std::string& name) const { Collection::const_iterator iter = find (name); - + return iter->second.second; } Globals::Data& Globals::operator[] (const std::string& name) { Collection::iterator iter = find (name); - + return iter->second.second; } - + void Globals::setInt (const std::string& name, int value) { Collection::iterator iter = find (name); - + switch (iter->second.first) { case 's': iter->second.second.mShort = value; break; case 'l': iter->second.second.mLong = value; break; case 'f': iter->second.second.mFloat = value; break; - + default: throw std::runtime_error ("unsupported global variable type"); } } - + void Globals::setFloat (const std::string& name, float value) { Collection::iterator iter = find (name); @@ -127,9 +127,9 @@ namespace MWWorld case 'f': iter->second.second.mFloat = value; break; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + int Globals::getInt (const std::string& name) const { Collection::const_iterator iter = find (name); @@ -141,13 +141,13 @@ namespace MWWorld case 'f': return iter->second.second.mFloat; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + float Globals::getFloat (const std::string& name) const { Collection::const_iterator iter = find (name); - + switch (iter->second.first) { case 's': return iter->second.second.mShort; @@ -155,16 +155,16 @@ namespace MWWorld case 'f': return iter->second.second.mFloat; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + char Globals::getType (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) return ' '; - + return iter->second.first; } } diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index aa870f9252..143d90034a 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -13,9 +13,9 @@ enum VarType { VT_Unknown, VT_None, - VT_Short, + VT_Short, // stored as a float, kinda VT_Int, - VT_Long, + VT_Long, // stored as a float VT_Float, VT_String, VT_Ignored diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index ceaa869489..429c6ff1d2 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -12,7 +12,7 @@ void Global::load(ESMReader &esm) if (tmp == "s") mType = VT_Short; else if (tmp == "l") - mType = VT_Int; + mType = VT_Long; else if (tmp == "f") mType = VT_Float; else @@ -30,7 +30,7 @@ void Global::save(ESMWriter &esm) esm.writeHNString("FNAM", "s"); break; - case VT_Int: + case VT_Long: esm.writeHNString("FNAM", "l"); break; From 1a43d86d9e33cb1a8351347d37eaeaedfebca47b Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 15:58:32 +0100 Subject: [PATCH 0499/1483] Close messages boxes with the activation key (Bug #589) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f7e1c8a845..5a6998d9ee 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -179,6 +179,11 @@ namespace MWInput case A_Activate: resetIdleTime(); activate(); + if( MWBase::Environment::get().getWindowManager()->isGuiMode() + && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) { + // Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button + MWBase::Environment::get().getWindowManager()->enterPressed(); + } break; case A_Journal: toggleJournal (); From b1ca719d61b4df9b5ebcfd58457640febbd7da51 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 16:37:59 +0100 Subject: [PATCH 0500/1483] Added click sound to OK button for message boxes --- apps/openmw/mwgui/messagebox.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 896ab3bb56..0ee042e326 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -1,6 +1,8 @@ #include #include "messagebox.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" using namespace MWGui; @@ -375,6 +377,7 @@ void InteractiveMessageBox::enterPressed() if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) { buttonActivated(*button); + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); break; } } From fb990b5e69d96865f490f5ea4f747ad64d571a51 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Feb 2013 17:08:34 +0100 Subject: [PATCH 0501/1483] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 535e922ae1..027dc09860 100644 --- a/credits.txt +++ b/credits.txt @@ -34,6 +34,7 @@ lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) Marcin Hulist (Gohan) +Manuel Edelmann (vorenon) Michael Mc Donnell Michael Papageorgiou (werdanith) Nathan Jeffords (blunted2night) From cd99e9d952d9a2b2b3f24425e678a83a1c9dd73c Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 26 Feb 2013 17:28:39 +0100 Subject: [PATCH 0502/1483] Updated credits.txt and corrected license info in readme.txt --- credits.txt | 58 +++++++++++++++++++++++++++++++++++------------------ readme.txt | 2 +- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/credits.txt b/credits.txt index 027dc09860..6f7e72aa1c 100644 --- a/credits.txt +++ b/credits.txt @@ -12,66 +12,74 @@ Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) Aleksandar Jovanov +Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) athile BrotherBrick -Chris Robinson +Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) Douglas Diniz (Dgdiniz) +Douglas Mencken (dougmencken) +Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 -Emanuel "potatoesmaster" Guével -gugus / gus +Emanuel Guével (potatoesmaster) +gugus/gus Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) Joel Graff (graffy) +Jordan Milne +Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) Marcin Hulist (Gohan) +Mark Siewert (mark76) Manuel Edelmann (vorenon) Michael Mc Donnell Michael Papageorgiou (werdanith) Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) +Nolan Poe (nopoe) +Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) +Radu-Marius Popovici (rpopovici) Roman Melnik (Kromgart) +Sandy Carter (bwrsandman) Sebastian Wick (swick) Sergey Shambir -Sylvain T. (Garvek) +Sylvain Thesnieres (Garvek) Tom Mason (wheybags) + Packagers: Alexander Olofsson (Ace) - Windows BrotherBrick - Ubuntu Linux -Edmondo Tommasina - Gentoo Linux +Edmondo Tommasina (edmondo) - Gentoo Linux +Julian Ospald (hasufell) - Gentoo Linux +Karl-Felix Glatzer (k1ll) - Linux Binaries Kenny Armstrong (artorius) - Fedora Linux Nikolay Kasyanov (corristo) - Mac OS X Sandy Carter (bwrsandman) - Arch Linux -Public Relations: -ElderTroll - Release Manager -sir_herrbatka - News Writer +Public Relations and Translations: +Julien Voisin (jvoisin/ap0) - French News Writer +Artem Kotsynyak (greye) - Russian News Writer +Pithorn - Chinese News Writer +sir_herrbatka - English/Polish News Writer WeirdSexy - Podcaster Website: -juanmnzsk8 - Spanish News Writer -Julien Voisin (jvoisin/ap0) - French News Writer -Kingpix - Italian News Writer Lukasz Gromanowski (lgro) - Website Administrator -Nikolay Kasyanov (corristo) - Russian News Writer -Okulo - Dutch News Writer -penguinroad - Indonesian News Writer Ryan Sardonic (Wry) - Wiki Editor -sir_herrbatka - Forum Admin/Polish News Writer -spyboot - German News Writer +sir_herrbatka - Forum Administrator Formula Research: @@ -87,20 +95,32 @@ Sadler Artwork: Necrod - OpenMW Logo -raevol - Wordpress Theme - +Mickey Lyle (raevol) - Wordpress Theme +Okulo - OpenMW Editor Icons Inactive Contributors: Ardekantur Armin Preiml +Carl Maxwell Diggory Hardy -Jan Borsodi +Dmitry Marakasov (AMDmi3) +ElderTroll +guidoj Jan-Peter Nilsson (peppe) +Jan Borsodi Josua Grawitter +juanmnzsk8 +Kingpix Lordrea +Michal Sciubidlo Nicolay Korslund +pchan3 +penguinroad +psi29a sergoz +spyboot Star-Demon +Thoronador Yuri Krupenin diff --git a/readme.txt b/readme.txt index 3124744c30..228278a919 100644 --- a/readme.txt +++ b/readme.txt @@ -9,7 +9,7 @@ Website: http://www.openmw.org Font Licenses: EBGaramond-Regular.ttf: OFL (see OFL.txt for more information) -VeraMono.ttf: custom (see Bitstream Vera License.txt for more information) +DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) From 21f502e3ddf191d67ff5569ac846a01574dcedc5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 26 Feb 2013 09:36:56 -0800 Subject: [PATCH 0503/1483] properly handle potentially non 16 bit planar audio formats --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 54df45ff4c..7e8751c598 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -134,6 +134,18 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) return dec; } +static AVSampleFormat ffmpegNonPlanarSampleFormat (AVSampleFormat format) +{ + switch (format) + { + case AV_SAMPLE_FMT_U8P: return AV_SAMPLE_FMT_U8; + case AV_SAMPLE_FMT_S16P: return AV_SAMPLE_FMT_S16; + case AV_SAMPLE_FMT_S32P: return AV_SAMPLE_FMT_S32; + case AV_SAMPLE_FMT_FLTP: return AV_SAMPLE_FMT_FLT; + case AV_SAMPLE_FMT_DBLP: return AV_SAMPLE_FMT_DBL; + default:return format; + } +} void FFmpeg_Decoder::open(const std::string &fname) { @@ -153,10 +165,6 @@ void FFmpeg_Decoder::open(const std::string &fname) try { - for(size_t j = 0;j < mFormatCtx->nb_streams;j++) - if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) - mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; - if(avformat_find_stream_info(mFormatCtx, NULL) < 0) fail("Failed to find stream info in "+fname); @@ -164,7 +172,6 @@ void FFmpeg_Decoder::open(const std::string &fname) { if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; mStream = &mFormatCtx->streams[j]; break; } @@ -172,6 +179,8 @@ void FFmpeg_Decoder::open(const std::string &fname) if(!mStream) fail("No audio streams in "+fname); + (*mStream)->codec->request_sample_fmt = ffmpegNonPlanarSampleFormat ((*mStream)->codec->sample_fmt); + AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id); if(!codec) { From ceafcc2ebbc4a86e4f5cbc6f188658a10fdc58b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Feb 2013 10:19:33 -0800 Subject: [PATCH 0504/1483] Support float samples with ffmpeg Requires the AL_EXT_FLOAT32 extension in OpenAL --- apps/openmw/mwrender/videoplayer.cpp | 2 ++ apps/openmw/mwsound/ffmpeg_decoder.cpp | 2 ++ apps/openmw/mwsound/openal_output.cpp | 45 +++++++++++++++++++++++++ apps/openmw/mwsound/sound_decoder.hpp | 3 +- apps/openmw/mwsound/soundmanagerimp.cpp | 2 ++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b710225042..a0dedb6bc2 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -404,6 +404,8 @@ public: *type = MWSound::SampleType_UInt8; else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = MWSound::SampleType_Int16; + else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT) + *type = MWSound::SampleType_Float32; else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 54df45ff4c..8c857f4ea1 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -224,6 +224,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * *type = SampleType_UInt8; else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = SampleType_Int16; + else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT) + *type = SampleType_Float32; else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name((*mStream)->codec->sample_fmt)); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 67008e2bcd..1dc5f9974f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -88,6 +88,51 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } } } + if(alIsExtensionPresent("AL_EXT_FLOAT32")) + { + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltfmtlist[] = { + { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, + { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, + }; + static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); + + for(size_t i = 0;i < fltfmtlistsize;i++) + { + if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) + { + ALenum format = alGetEnumValue(fltfmtlist[i].name); + if(format != 0 && format != -1) + return format; + } + } + if(alIsExtensionPresent("AL_EXT_MCFORMATS")) + { + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltmcfmtlist[] = { + { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, + { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, + { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, + }; + static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); + + for(size_t i = 0;i < fltmcfmtlistsize;i++) + { + if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) + { + ALenum format = alGetEnumValue(fltmcfmtlist[i].name); + if(format != 0 && format != -1) + return format; + } + } + } + } fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); return AL_NONE; diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 29d99e8fa4..151b580360 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -9,7 +9,8 @@ namespace MWSound { enum SampleType { SampleType_UInt8, - SampleType_Int16 + SampleType_Int16, + SampleType_Float32 }; const char *getSampleTypeName(SampleType type); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c502906808..1b07dfe627 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -607,6 +607,7 @@ namespace MWSound { case SampleType_UInt8: return "U8"; case SampleType_Int16: return "S16"; + case SampleType_Float32: return "Float32"; } return "(unknown sample type)"; } @@ -638,6 +639,7 @@ namespace MWSound { case SampleType_UInt8: frames *= 1; break; case SampleType_Int16: frames *= 2; break; + case SampleType_Float32: frames *= 4; break; } return frames; } From 13c33c1613adce9e7bf5b81debfe4922f3412734 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 19:37:47 +0100 Subject: [PATCH 0505/1483] added missing click sound to main menu --- apps/openmw/mwgui/mainmenu.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 14309abc5e..5402d35428 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -5,6 +5,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" namespace MWGui { @@ -65,6 +66,7 @@ namespace MWGui void MainMenu::onButtonClicked(MyGUI::Widget *sender) { + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); if (sender == mButtons["return"]) MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); else if (sender == mButtons["options"]) From 89cba3cf455109e661d7e3db2139a7873628cfa5 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 19:52:51 +0100 Subject: [PATCH 0506/1483] Replaced ifs/elseifs with switch --- apps/openmw/mwgui/waitdialog.cpp | 65 ++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 2c74dd2fd6..794a9ab55f 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -95,31 +95,46 @@ namespace MWGui // http://www.uesp.net/wiki/Lore:Calendar std::string month; int m = MWBase::Environment::get().getWorld ()->getMonth (); - if (m == 0) - month = "#{sMonthMorningstar}"; - else if (m == 1) - month = "#{sMonthSunsdawn}"; - else if (m == 2) - month = "#{sMonthFirstseed}"; - else if (m == 3) - month = "#{sMonthRainshand}"; - else if (m == 4) - month = "#{sMonthSecondseed}"; - else if (m == 5) - month = "#{sMonthMidyear}"; - else if (m == 6) - month = "#{sMonthSunsheight}"; - else if (m == 7) - month = "#{sMonthLastseed}"; - else if (m == 8) - month = "#{sMonthHeartfire}"; - else if (m == 9) - month = "#{sMonthFrostfall}"; - else if (m == 10) - month = "#{sMonthSunsdusk}"; - else if (m == 11) - month = "#{sMonthEveningstar}"; - + switch (m) { + case 0: + month = "#{sMonthMorningstar}"; + break; + case 1: + month = "#{sMonthSunsdawn}"; + break; + case 2: + month = "#{sMonthFirstseed}"; + break; + case 3: + month = "#{sMonthRainshand}"; + break; + case 4: + month = "#{sMonthSecondseed}"; + break; + case 5: + month = "#{sMonthMidyear}"; + break; + case 6: + month = "#{sMonthSunsheight}"; + break; + case 7: + month = "#{sMonthLastseed}"; + break; + case 8: + month = "#{sMonthHeartfire}"; + break; + case 9: + month = "#{sMonthFrostfall}"; + break; + case 10: + month = "#{sMonthSunsdusk}"; + break; + case 11: + month = "#{sMonthEveningstar}"; + break; + default: + break; + } int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); bool pm = hour >= 12; if (hour >= 13) hour -= 12; From 6b86db6b6fa7ff0a5020a4d95baa0da6ee6e9567 Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 26 Feb 2013 20:49:20 +0100 Subject: [PATCH 0507/1483] Forgot the release manager and added the license terms of EB Garamond --- credits.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/credits.txt b/credits.txt index 6f7e72aa1c..d1e85c6904 100644 --- a/credits.txt +++ b/credits.txt @@ -69,8 +69,9 @@ Sandy Carter (bwrsandman) - Arch Linux Public Relations and Translations: -Julien Voisin (jvoisin/ap0) - French News Writer Artem Kotsynyak (greye) - Russian News Writer +Julien Voisin (jvoisin/ap0) - French News Writer +Mickey Lyle (raevol) - Release Manager Pithorn - Chinese News Writer sir_herrbatka - English/Polish News Writer WeirdSexy - Podcaster @@ -138,7 +139,7 @@ Thanks to Kevin Ryan, for creating the icon used for the Data Files tab of the OpenMW Launcher. Thanks to Georg Duffner, -for the open-source EB Garamond fontface. +for his EB Garamond fontface, see OFL.txt for his license terms. Thanks to Dongle, for his Daedric fontface, see Daedric Font License.txt for his license terms. From 759b2e96bf77a97cc0f2c713c2700ba51024791c Mon Sep 17 00:00:00 2001 From: lazydev Date: Wed, 27 Feb 2013 01:37:40 +0400 Subject: [PATCH 0508/1483] fix for https://bugs.openmw.org/issues/577 --- components/esm/loadcell.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 7400fd026c..92cb7d5ce8 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -112,8 +112,8 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) // instead. if (mData.mFlags & QuasiEx) mRegion = esm.getHNOString("RGNN"); - else - esm.getHNT(mAmbi, "AMBI", 16); + else if (esm.isNextSub("AMBI")) + esm.getHT(mAmbi); } else { @@ -126,7 +126,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) if (esm.isNextSub("NAM0")) { esm.getHT(mNAM0); } - + // preload moved references while (esm.isNextSub("MVRF")) { CellRef ref; @@ -135,7 +135,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) MWWorld::Store &cStore = const_cast&>(store.get()); ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); - + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // implementation when the oher implementation works as well. getNextRef(esm, ref); @@ -143,7 +143,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - + // Add data required to make reference appear in the correct cell. // We should not need to test for duplicates, as this part of the code is pre-cell merge. mMovedRefs.push_back(cMRef); @@ -186,7 +186,7 @@ void Cell::save(ESMWriter &esm) if (mMapColor != 0) esm.writeHNT("NAM5", mMapColor); } - + if (mNAM0 != 0) esm.writeHNT("NAM0", mNAM0); } @@ -226,7 +226,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); - + // Identify references belonging to a parent file and adapt the ID accordingly. int local = (ref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; @@ -249,7 +249,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // missing ref.mScale = 1.0; esm.getHNOT(ref.mScale, "XSCL"); - + // TODO: support loading references from saves, there are tons of keys not recognized yet. // The following is just an incomplete list. if (esm.isNextSub("ACTN")) @@ -266,7 +266,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.skipHSub(); else if (esm.isNextSub("CRED")) // ??? esm.skipHSub(); - + ref.mOwner = esm.getHNOString("ANAM"); ref.mGlob = esm.getHNOString("BNAM"); ref.mSoul = esm.getHNOString("XSOL"); @@ -305,7 +305,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNOT(ref.mFltv, "FLTV"); esm.getHNOT(ref.mPos, "DATA", 24); - + // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. @@ -318,7 +318,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHT(ref.mNam0); //esm.getHNOT(NAM0, "NAM0"); } - + if (esm.isNextSub("DELE")) { esm.skipHSub(); ref.mDeleted = 2; // Deleted, will not respawn. @@ -333,7 +333,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) { esm.getHT(mref.mRefnum); esm.getHNOT(mref.mTarget, "CNDT"); - + // Identify references belonging to a parent file and adapt the ID accordingly. int local = (mref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; From b4b20622c670bb15b78ede194f4f57a99b9f36b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Feb 2013 15:24:20 -0800 Subject: [PATCH 0509/1483] Properly handle NiAlphaProperty values --- components/nifogre/ogre_nif_loader.cpp | 139 ++++++++++--------------- 1 file changed, 57 insertions(+), 82 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5b84807a47..5042f666a5 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -492,49 +492,43 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; -// Conversion of blend / test mode from NIF -> OGRE. -// Not in use yet, so let's comment it out. -/* -static SceneBlendFactor getBlendFactor(int mode) +// Conversion of blend / test mode from NIF +static const char *getBlendFactor(int mode) { - switch(mode) + switch(mode) { - case 0: return SBF_ONE; - case 1: return SBF_ZERO; - case 2: return SBF_SOURCE_COLOUR; - case 3: return SBF_ONE_MINUS_SOURCE_COLOUR; - case 4: return SBF_DEST_COLOUR; - case 5: return SBF_ONE_MINUS_DEST_COLOUR; - case 6: return SBF_SOURCE_ALPHA; - case 7: return SBF_ONE_MINUS_SOURCE_ALPHA; - case 8: return SBF_DEST_ALPHA; - case 9: return SBF_ONE_MINUS_DEST_ALPHA; - // [Comment from Chris Robinson:] Can't handle this mode? :/ - // case 10: return SBF_SOURCE_ALPHA_SATURATE; - default: - return SBF_SOURCE_ALPHA; + case 0: return "one"; + case 1: return "zero"; + case 2: return "src_colour"; + case 3: return "one_minus_src_colour"; + case 4: return "dest_colour"; + case 5: return "one_minus_dest_colour"; + case 6: return "src_alpha"; + case 7: return "one_minus_src_alpha"; + case 8: return "dest_alpha"; + case 9: return "one_minus_dest_alpha"; + case 10: return "src_alpha_saturate"; } + std::cerr<< "Unexpected blend mode: "<data->colors.size() != 0); @@ -640,7 +634,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String if (a) { alphaFlags = a->flags; -// alphaTest = a->data.threshold; + alphaTest = a->data.threshold; } // Material @@ -674,6 +668,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, texName); boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); + boost::hash_combine(h, alphaTest); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -705,57 +700,37 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty ("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Add transparency if NiAlphaProperty was present - if (alphaFlags != -1) + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); + if (result.first) { - // The 237 alpha flags are by far the most common. Check - // NiAlphaProperty in nif/property.h if you need to decode - // other values. 237 basically means normal transparencly. - if (alphaFlags == 237) - { - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); - if (result.first) - { - instance->setProperty("alpha_rejection", - sh::makeProperty(new sh::StringValue("greater_equal " + boost::lexical_cast(result.second)))); - } - else - { - // Enable transparency - instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); - } - } - else - warn("Unhandled alpha setting for texture " + texName); + alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ + alphaTest = result.second; + } + + if((alphaFlags&1)) + { + std::string blend_mode; + blend_mode += getBlendFactor((alphaFlags>>1)&0xf); + blend_mode += " "; + blend_mode += getBlendFactor((alphaFlags>>5)&0xf); + + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); + instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); } else - instance->getMaterial ()->setShadowCasterMaterial ("openmw_shadowcaster_noalpha"); + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - // As of yet UNTESTED code from Chris: - /*pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); - pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); - pass->setDepthCheckEnabled(true); - - // Add transparency if NiAlphaProperty was present - if (alphaFlags != -1) + if((alphaFlags>>9)&1) { - std::cout << "Alpha flags set!" << endl; - if ((alphaFlags&1)) - { - pass->setDepthWriteEnabled(false); - pass->setSceneBlending(getBlendFactor((alphaFlags>>1)&0xf), - getBlendFactor((alphaFlags>>5)&0xf)); - } - else - pass->setDepthWriteEnabled(true); - - if ((alphaFlags>>9)&1) - pass->setAlphaRejectSettings(getTestMode((alphaFlags>>10)&0x7), - alphaTest); - - pass->setTransparentSortingEnabled(!((alphaFlags>>13)&1)); + std::string reject; + reject += getTestMode((alphaFlags>>10)&0x7); + reject += " "; + reject += Ogre::StringConverter::toString(alphaTest); + instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } -*/ + + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(((alphaFlags>>13)&1) ? + "off" : "on"))); return matname; } From f994b7d227bd2639882f5f8a1b525bff6db77c9f Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 27 Feb 2013 07:44:35 +0400 Subject: [PATCH 0510/1483] Prepare .desktop file for more systems This brings condition for .desktop file preparation in sync with condition for its installation. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6929850b51..dbab836907 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,7 +297,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg.install") -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") +if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") endif() From 9b0ac4e2998facb18cd7b055d8371893c5588f89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Feb 2013 09:20:42 +0100 Subject: [PATCH 0511/1483] NPCs / creatures can now emit ripples --- apps/openmw/mwrender/actors.cpp | 9 ++ apps/openmw/mwrender/actors.hpp | 7 +- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 127 ++++++++++++---------- apps/openmw/mwrender/renderingmanager.hpp | 9 ++ apps/openmw/mwrender/ripplesimulation.cpp | 89 +++++++++++---- apps/openmw/mwrender/ripplesimulation.hpp | 22 +++- apps/openmw/mwrender/water.cpp | 26 +++-- apps/openmw/mwrender/water.hpp | 12 +- 9 files changed, 205 insertions(+), 98 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 83c07737ce..644d3613bd 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,6 +6,8 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" +#include "../mwrender/renderingmanager.hpp" + #include "animation.hpp" #include "activatoranimation.hpp" #include "creatureanimation.hpp" @@ -72,6 +74,7 @@ void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv) NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), inv, RV_Actors); delete mAllActors[ptr]; mAllActors[ptr] = anim; + mRendering->addWaterRippleEmitter (ptr); } void Actors::insertCreature (const MWWorld::Ptr& ptr) { @@ -79,6 +82,7 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr) CreatureAnimation* anim = new CreatureAnimation(ptr); delete mAllActors[ptr]; mAllActors[ptr] = anim; + mRendering->addWaterRippleEmitter (ptr); } void Actors::insertActivator (const MWWorld::Ptr& ptr) { @@ -90,6 +94,8 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr) bool Actors::deleteObject (const MWWorld::Ptr& ptr) { + mRendering->removeWaterRippleEmitter (ptr); + delete mAllActors[ptr]; mAllActors.erase(ptr); @@ -120,6 +126,7 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) { if(iter->first.getCell() == store) { + mRendering->removeWaterRippleEmitter (iter->first); delete iter->second; mAllActors.erase(iter++); } @@ -172,6 +179,8 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) anim->updatePtr(cur); mAllActors[cur] = anim; } + + mRendering->updateWaterRippleEmitterPtr (old, cur); } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 75a18ba915..bba2d945c2 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -13,6 +13,7 @@ namespace MWWorld namespace MWRender { class Animation; + class RenderingManager; class Actors { @@ -20,13 +21,17 @@ namespace MWRender typedef std::map PtrAnimationMap; OEngine::Render::OgreRenderer &mRend; + MWRender::RenderingManager* mRendering; Ogre::SceneNode* mRootNode; CellSceneNodeMap mCellSceneNodes; PtrAnimationMap mAllActors; public: - Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} + Actors(OEngine::Render::OgreRenderer& _rend, MWRender::RenderingManager* rendering) + : mRend(_rend) + , mRendering(rendering) + {} ~Actors(); void setRootNode(Ogre::SceneNode* root); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 8cf4ff123e..8460d67aae 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -32,7 +32,7 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mLight = mRendering->getScene()->createLight(); mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLight->setDirection (Ogre::Vector3(0.3, 0.3, -0.7)); mLight->setVisible (false); mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9ef705fde4..943208a66b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -51,7 +51,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) : mRendering(_rend) , mObjects(mRendering) - , mActors(mRendering) + , mActors(mRendering, this) , mAmbientMode(0) , mSunEnabled(0) , mPhysicsEngine(engine) @@ -136,7 +136,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - sh::Factory::getInstance ().setSharedParameter ("viewportBackground", sh::makeProperty (new sh::Vector3(0,0,0))); sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); @@ -173,6 +172,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); + mWater = new MWRender::Water(mRendering.getCamera(), this); + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -222,15 +223,12 @@ void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) void RenderingManager::removeWater () { - if(mWater){ - mWater->setActive(false); - } + mWater->setActive(false); } void RenderingManager::toggleWater() { - if (mWater) - mWater->toggle(); + mWater->toggle(); } void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) @@ -321,6 +319,20 @@ RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr & void RenderingManager::update (float duration, bool paused) { + MWBase::World *world = MWBase::Environment::get().getWorld(); + + // player position + MWWorld::RefData &data = + MWBase::Environment::get() + .getWorld() + ->getPlayer() + .getPlayer() + .getRefData(); + float *_playerPos = data.getPosition().pos; + Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); + + Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); + Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -343,6 +355,17 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); + /* + if (world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)) + { + mFogColour = Ogre::ColourValue(0.18039, 0.23137, 0.25490); + mFogStart = 0; + mFogEnd = 1500; + } + */ + + applyFog(); + if(paused) { return; @@ -358,41 +381,21 @@ void RenderingManager::update (float duration, bool paused) mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); - MWWorld::RefData &data = - MWBase::Environment::get() - .getWorld() - ->getPlayer() - .getPlayer() - .getRefData(); - - float *fpos = data.getPosition().pos; - - // only for LocalMap::updatePlayer() - Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - Ogre::SceneNode *node = data.getBaseNode(); //Ogre::Quaternion orient = //node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); Ogre::Quaternion orient = node->_getDerivedOrientation(); - mLocalMap->updatePlayer(pos, orient); + mLocalMap->updatePlayer(playerPos, orient); - if (mWater) { - Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); + mWater->updateUnderwater( + world->isUnderwater( + world->getPlayer().getPlayer().getCell(), + cam) + ); - MWBase::World *world = MWBase::Environment::get().getWorld(); - - mWater->updateUnderwater( - world->isUnderwater( - world->getPlayer().getPlayer().getCell(), - cam) - ); - - // MW to ogre coordinates - orig = Ogre::Vector3(orig.x, orig.z, -orig.y); - mWater->update(duration, orig); - } + mWater->update(duration, playerPos); } void RenderingManager::preRenderTargetUpdate(const RenderTargetEvent &evt) @@ -416,10 +419,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) || ((store->mCell->isExterior()) && !lands.search(store->mCell->getGridX(),store->mCell->getGridY()) )) // always use water, if the cell does not have land. { - if(mWater == 0) - mWater = new MWRender::Water(mRendering.getCamera(), this, store->mCell); - else - mWater->changeCell(store->mCell); + mWater->changeCell(store->mCell); mWater->setActive(true); } else @@ -428,8 +428,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) void RenderingManager::setWaterHeight(const float height) { - if (mWater) - mWater->setHeight(height); + mWater->setHeight(height); } void RenderingManager::skyEnable () @@ -521,24 +520,26 @@ void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) { + mFogColour = colour; float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance"); - float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); - float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); - - mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high); - - mRendering.getCamera()->setFarClipDistance ( max / density ); - mRendering.getViewport()->setBackgroundColour (colour); - - if (mWater) - mWater->setViewportBackground (colour); - - sh::Factory::getInstance ().setSharedParameter ("viewportBackground", - sh::makeProperty (new sh::Vector3(colour.r, colour.g, colour.b))); + mFogStart = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); + mFogEnd = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); + mRendering.getCamera()->setFarClipDistance ( Settings::Manager::getFloat("max viewing distance", "Viewing distance") / density ); } +void RenderingManager::applyFog () +{ + mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); + + mRendering.getViewport()->setBackgroundColour (mFogColour); + + mWater->setViewportBackground (mFogColour); + + sh::Factory::getInstance ().setSharedParameter ("viewportBackground", + sh::makeProperty (new sh::Vector3(mFogColour.r, mFogColour.g, mFogColour.b))); +} void RenderingManager::setAmbientMode() { @@ -826,8 +827,7 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } - if (mWater) - mWater->processChangedSettings(settings); + mWater->processChangedSettings(settings); if (rebuild) mObjects.rebuildStaticGeometry(); @@ -902,6 +902,8 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) MWWorld::Class::get(ptr).getInventoryStore(ptr), RV_Actors ); mPlayer->setAnimation(anim); + mWater->removeEmitter (ptr); + mWater->addEmitter (ptr); } void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw) @@ -945,4 +947,19 @@ void RenderingManager::stopVideo() mVideoPlayer->stopVideo (); } +void RenderingManager::addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale, float force) +{ + mWater->addEmitter (ptr, scale, force); +} + +void RenderingManager::removeWaterRippleEmitter (const MWWorld::Ptr& ptr) +{ + mWater->removeEmitter (ptr); +} + +void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + mWater->updateEmitterPtr(old, ptr); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5d79f80aa7..02d796fddf 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -163,6 +163,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void skySetMoonColour (bool red); void configureAmbient(MWWorld::CellStore &mCell); + void addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeWaterRippleEmitter (const MWWorld::Ptr& ptr); + void updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void requestMap (MWWorld::CellStore* cell); ///< request the local map for a cell @@ -204,6 +208,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList sh::Factory* mFactory; void setAmbientMode(); + void applyFog(); void setMenuTransparency(float val); @@ -234,6 +239,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::SceneNode *mRootNode; + Ogre::ColourValue mFogColour; + float mFogStart; + float mFogEnd; + OEngine::Physic::PhysicEngine* mPhysicsEngine; MWRender::Player *mPlayer; diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 6c9264b608..47fbc8ddf6 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -7,6 +7,11 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" + namespace MWRender { @@ -21,8 +26,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) mRippleAreaLength(1000), mImpulseSize(20), mTexelOffset(0,0), - mFirstUpdate(true), - mLastPos(0,0) + mFirstUpdate(true) { Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); @@ -142,34 +146,39 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); } -void RippleSimulation::addImpulse(Ogre::Vector2 position, float scale, float force) -{ - // don't emit if there wasn't enough movement - /// \todo this should be done somewhere else, otherwise multiple emitters cannot be supported - if ((position - mLastPos).length () <= 2) - return; - - mLastPos = position; - - /// \todo scale, force - mImpulses.push(position); -} - void RippleSimulation::addImpulses() { mRectangle->setVisible(false); mImpulse->setVisible(true); - while (mImpulses.size()) + /// \todo it should be more efficient to render all emitters at once + for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) { - Ogre::Vector2 pos = mImpulses.front(); - pos -= mRippleCenter; - pos /= mRippleAreaLength; - float size = mImpulseSize / mRippleAreaLength; - mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); - mImpulses.pop(); + if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()) + { + // fetch a new ptr (to handle cell change etc) + // for non-player actors this is done in updateObjectCell + it->mPtr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); + } + float* _currentPos = it->mPtr.getRefData().getPosition().pos; + Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]); - mRenderTargets[1]->update(); + if ( (currentPos - it->mLastEmitPosition).length() > 2 + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), currentPos)) + { + it->mLastEmitPosition = currentPos; + + Ogre::Vector2 pos (currentPos.x, currentPos.y); + pos -= mRippleCenter; + pos /= mRippleAreaLength; + float size = mImpulseSize / mRippleAreaLength; + mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); + + // don't render if we are offscreen + if (pos.x - size >= 1.0 || pos.y+size <= -1.0 || pos.x+size <= -1.0 || pos.y-size >= 1.0) + continue; + mRenderTargets[1]->update(); + } } mImpulse->setVisible(false); @@ -216,5 +225,39 @@ void RippleSimulation::swapHeightMaps() mTextures[2] = tmp2; } +void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) +{ + Emitter newEmitter; + newEmitter.mPtr = ptr; + newEmitter.mScale = scale; + newEmitter.mForce = force; + newEmitter.mLastEmitPosition = Ogre::Vector3(0,0,0); + mEmitters.push_back (newEmitter); +} + +void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == ptr) + { + mEmitters.erase(it); + return; + } + } +} + +void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == old) + { + it->mPtr = ptr; + return; + } + } +} + } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 2f8cae24fd..7e7eebc1cf 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -4,6 +4,9 @@ #include #include #include +#include + +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -16,6 +19,14 @@ namespace Ogre namespace MWRender { +struct Emitter +{ + MWWorld::Ptr mPtr; + Ogre::Vector3 mLastEmitPosition; + float mScale; + float mForce; +}; + class RippleSimulation { public: @@ -24,9 +35,14 @@ public: void update(float dt, Ogre::Vector2 position); - void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); + /// adds an emitter, position will be tracked automatically + void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::Ptr& ptr); + void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); private: + std::vector mEmitters; + Ogre::RenderTexture* mRenderTargets[4]; Ogre::TexturePtr mTextures[4]; @@ -34,8 +50,6 @@ private: float mRippleAreaLength; float mImpulseSize; - Ogre::Vector2 mLastPos; - bool mFirstUpdate; Ogre::Camera* mCamera; @@ -51,8 +65,6 @@ private: Ogre::Rectangle2D* mImpulse; - std::queue mImpulses; - void addImpulses(); void heightMapToNormalMap(); void waterSimulation(); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7d6ca1a0d0..d112e17b2c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -81,6 +81,7 @@ void CubeReflection::update () PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) : Reflection(sceneManager) , mSky(sky) + , mRenderActive(false) { mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); mSceneMgr->addRenderQueueListener(this); @@ -186,7 +187,7 @@ void PlaneReflection::setVisibilityMask (int flags) // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mActive(1), mToggled(1), @@ -202,7 +203,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mMaterial = MaterialManager::getSingleton().getByName("Water"); - mTop = cell->mWater; + mTop = 0; mIsUnderwater = false; @@ -216,10 +217,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - if(!(cell->mData.mFlags & cell->Interior)) - { - mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY)); - } mWaterNode->attachObject(mWater); applyRTT(); @@ -397,7 +394,7 @@ void Water::update(float dt, Ogre::Vector3 player) { //mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } - mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); + mSimulation->update(dt, Ogre::Vector2(player.x, player.y)); if (mReflection) mReflection->update(); @@ -499,10 +496,19 @@ void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& co } } -void Water::addImpulse (Vector2 position, float scale, float force) +void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) { - if (mSimulation) - mSimulation->addImpulse (position, scale, force); + mSimulation->addEmitter (ptr, scale, force); +} + +void Water::removeEmitter (const MWWorld::Ptr& ptr) +{ + mSimulation->removeEmitter (ptr); +} + +void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + mSimulation->updateEmitterPtr(old, ptr); } } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index eb7d98f5da..ddf6ef7ab7 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -11,9 +11,12 @@ #include #include +#include + + #include "renderconst.hpp" -#include +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -138,7 +141,7 @@ namespace MWRender { RippleSimulation* mSimulation; public: - Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); + Water (Ogre::Camera *camera, RenderingManager* rend); ~Water(); void setActive(bool active); @@ -146,7 +149,10 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); - void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); + /// adds an emitter, position will be tracked automatically using its scene node + void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::Ptr& ptr); + void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); void setViewportBackground(const Ogre::ColourValue& bg); From 0bc4c3556ae9f9c10e9197fb1ce18aab49a824c1 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 27 Feb 2013 15:58:01 +0100 Subject: [PATCH 0512/1483] Fix dialogue gender filter --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 09bb0ddc4c..6f9d8b42fc 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -289,7 +289,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con case SelectWrapper::Function_PcGender: - return player.get()->mBase->mFlags & ESM::NPC::Female ? 0 : 1; + return player.get()->mBase->isMale() ? 0 : 1; case SelectWrapper::Function_PcClothingModifier: { From 8966e88050a167e1bd6f40bcfd1376bdabc13ba4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Feb 2013 16:07:15 +0100 Subject: [PATCH 0513/1483] Fix shadows --- files/materials/objects.shader | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index d8498b8313..88ca2d1524 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -32,8 +32,11 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) +#if (VIEWPROJ_FIX) || (SHADOWS) + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif + #if VIEWPROJ_FIX - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) shUniform(float4x4, vpMatrix) @shAutoConstant(vpMatrix, viewproj_matrix) #endif From be9d49c510ea56aaca83e8c80456a70810ce2bef Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 27 Feb 2013 16:15:59 +0100 Subject: [PATCH 0514/1483] Do not hide pinned windows during loadings --- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1dc11f2c44..e17190b023 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -424,6 +424,12 @@ void WindowManager::updateVisible() MyGUI::PointerManager::getInstance().setVisible(false); break; case GM_Loading: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + MyGUI::PointerManager::getInstance().setVisible(false); break; case GM_Video: From 03ca7f6123e250222bc133f9017f5d8b0aa5e01b Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Wed, 27 Feb 2013 23:45:09 +0400 Subject: [PATCH 0515/1483] NIF: added NiStencilProperty record handling NiStencilProperty appears in Better Clothes plugin. If it not handled, some parts of NPCs bodies will be not rendered. --- components/nif/nif_file.cpp | 1 + components/nif/nif_file.hpp | 1 + components/nif/property.hpp | 57 ++++++++++++++++++++++++++ components/nif/record.hpp | 1 + components/nifogre/ogre_nif_loader.cpp | 2 + 5 files changed, 62 insertions(+) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 58d1bc9b85..ba3a7513b2 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -256,6 +256,7 @@ void NIFFile::parse() else if(rec == "NiDitherProperty") { r = new NiDitherProperty; r->recType = RC_NiDitherProperty; } else if(rec == "NiWireframeProperty") { r = new NiWireframeProperty; r->recType = RC_NiWireframeProperty; } else if(rec == "NiSpecularProperty") { r = new NiSpecularProperty; r->recType = RC_NiSpecularProperty; } + else if(rec == "NiStencilProperty") { r = new NiStencilProperty; r->recType = RC_NiStencilProperty; } // Controllers else if(rec == "NiVisController") { r = new NiVisController; r->recType = RC_NiVisController; } diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index e8884cd4d4..5e9694f4b4 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -158,6 +158,7 @@ public: short getShort() { return read_le16(); } unsigned short getUShort() { return read_le16(); } int getInt() { return read_le32(); } + unsigned int getUInt() { return read_le32(); } float getFloat() { return read_le32f(); } Ogre::Vector2 getVector2() { diff --git a/components/nif/property.hpp b/components/nif/property.hpp index b24e49b479..046fb04652 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -257,9 +257,66 @@ struct S_AlphaProperty } }; +/* + Docs taken from: + http://niftools.sourceforge.net/doc/nif/NiStencilProperty.html + */ +struct S_StencilProperty +{ + // Is stencil test enabled? + unsigned char enabled; + + /* + 0 TEST_NEVER + 1 TEST_LESS + 2 TEST_EQUAL + 3 TEST_LESS_EQUAL + 4 TEST_GREATER + 5 TEST_NOT_EQUAL + 6 TEST_GREATER_EQUAL + 7 TEST_ALWAYS + */ + int compareFunc; + unsigned stencilRef; + unsigned stencilMask; + /* + Stencil test fail action, depth test fail action and depth test pass action: + 0 ACTION_KEEP + 1 ACTION_ZERO + 2 ACTION_REPLACE + 3 ACTION_INCREMENT + 4 ACTION_DECREMENT + 5 ACTION_INVERT + */ + int failAction; + int zFailAction; + int zPassAction; + /* + Face draw mode: + 0 DRAW_CCW_OR_BOTH + 1 DRAW_CCW [default] + 2 DRAW_CW + 3 DRAW_BOTH + */ + int drawMode; + + void read(NIFFile *nif) + { + enabled = nif->getChar(); + compareFunc = nif->getInt(); + stencilRef = nif->getUInt(); + stencilMask = nif->getUInt(); + failAction = nif->getInt(); + zFailAction = nif->getInt(); + zPassAction = nif->getInt(); + drawMode = nif->getInt(); + } +}; + typedef StructPropT NiAlphaProperty; typedef StructPropT NiMaterialProperty; typedef StructPropT NiVertexColorProperty; +typedef StructPropT NiStencilProperty; } // Namespace #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index d5f65e83a3..073f4657c0 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -48,6 +48,7 @@ enum RecordType RC_NiDitherProperty, RC_NiWireframeProperty, RC_NiSpecularProperty, + RC_NiStencilProperty, RC_NiVisController, RC_NiGeomMorpherController, RC_NiKeyframeController, diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5042f666a5..052334f1da 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -586,6 +586,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String m = static_cast(pr); else if (pr->recType == Nif::RC_NiAlphaProperty) a = static_cast(pr); + else if (pr->recType == Nif::RC_NiStencilProperty) + /* unused */; else warn("Skipped property type: "+pr->recName); } From bfe80bb8dc0fa780ab065bb2086a4a7fc6663016 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 27 Feb 2013 12:33:36 -0800 Subject: [PATCH 0516/1483] Avoid duplicating skeletons due to casing issues Manually created resource names are apparently always case sensitive, causing some skeletons to get loaded multiple times. --- apps/openmw/mwrender/animation.cpp | 15 ++------ components/nifogre/ogre_nif_loader.cpp | 51 ++++++++++++++------------ components/nifogre/ogre_nif_loader.hpp | 2 +- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 394e25b504..cc926e685d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -53,8 +53,6 @@ void Animation::setAnimationSources(const std::vector &names) if(!mEntityList.mSkelBase) return; - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - mCurrentAnim = NULL; mCurrentKeys = NULL; mAnimVelocity = 0.0f; @@ -62,19 +60,14 @@ void Animation::setAnimationSources(const std::vector &names) mNonAccumRoot = NULL; mSkeletonSources.clear(); - std::vector::const_iterator nameiter = names.begin(); + std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { - Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); + Ogre::SkeletonPtr skel = NifOgre::Loader::getSkeleton(*nameiter); if(skel.isNull()) { - NifOgre::Loader::createSkeleton(*nameiter); - skel = skelMgr.getByName(*nameiter); - if(skel.isNull()) - { - std::cerr<< "Failed to get skeleton source "<<*nameiter <touch(); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5042f666a5..b3d70bb1fe 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -452,7 +452,8 @@ void loadResource(Ogre::Resource *resource) } } -bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) + +static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { /* We need to be a little aggressive here, since some NIFs have a crap-ton * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: @@ -463,7 +464,7 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif if(!node->boneTrafo) { if(node->recType == Nif::RC_NiTriShape) - return false; + return Ogre::SkeletonPtr(); if(node->controller.empty() && node->name != "AttachLight") { if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) @@ -474,18 +475,18 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif { if(!children[i].empty()) { - if(createSkeleton(name, group, children[i].getPtr())) - return true; + Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); + if(!skel.isNull()) + return skel; } } - return false; + return Ogre::SkeletonPtr(); } } } Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - skelMgr.create(name, group, true, &sLoaders[name]); - return true; + return skelMgr.create(name, group, true, &sLoaders[name]); } }; @@ -1140,10 +1141,7 @@ MeshInfoList Loader::load(const std::string &name, const std::string &group) bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); if(!hasSkel) - { - NIFSkeletonLoader skelldr; - hasSkel = skelldr.createSkeleton(name, group, node); - } + hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); NIFMeshLoader meshldr(name, group); if(hasSkel) @@ -1253,30 +1251,35 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } -bool Loader::createSkeleton(const std::string &name, const std::string &group) +Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group) { - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) + Ogre::SkeletonPtr skel; + + Misc::StringUtils::toLower(name); + skel = Ogre::SkeletonManager::getSingleton().getByName(name); + if(!skel.isNull()) + return skel; + + Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); + if(nif->numRecords() < 1) { - nif.warn("Found no NIF records in "+name+"."); - return false; + nif->warn("Found no NIF records in "+name+"."); + return skel; } // The first record is assumed to be the root node - Nif::Record const *r = nif.getRecord(0); + const Nif::Record *r = nif->getRecord(0); assert(r != NULL); - Nif::Node const *node = dynamic_cast(r); + const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return false; + nif->warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return skel; } - NIFSkeletonLoader skelldr; - return skelldr.createSkeleton(name, group, node); + return NIFSkeletonLoader::createSkeleton(name, group, node); } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 7a7b0c5a1e..eae37dd8a9 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -74,7 +74,7 @@ public: std::string name, const std::string &group="General"); - static bool createSkeleton(const std::string &name, const std::string &group="General"); + static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); }; } From 3ed0bf97a8a94d98e5d274f7a45a2f72e0b0bb63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 27 Feb 2013 13:16:27 -0800 Subject: [PATCH 0517/1483] Share the space with the parent entity only when there's real skinned meshes The existence of a base skeleton doesn't mean it shares the same bone structure. If there isn't an actual skinned entity besides the base, simply attach it to the bone like unskinned meshes should be. --- components/nifogre/ogre_nif_loader.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b3d70bb1fe..4d047ae8bb 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1204,14 +1204,20 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(meshes.size() == 0) return entitylist; + bool isskinned = false; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); std::string filter = "@shape=tri "+bonename; Misc::StringUtils::toLower(filter); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); - if(!entitylist.mSkelBase && ent->hasSkeleton()) - entitylist.mSkelBase = ent; + if(!entitylist.mSkelBase) + { + if(ent->hasSkeleton()) + entitylist.mSkelBase = ent; + } + else if(!isskinned && ent->hasSkeleton()) + isskinned = true; entitylist.mEntities.push_back(ent); } @@ -1219,7 +1225,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(bonename.find("Left") != std::string::npos) scale.x *= -1.0f; - if(entitylist.mSkelBase) + if(isskinned) { for(size_t i = 0;i < entitylist.mEntities.size();i++) { From b93eb844010f3002bb1acb15534f82f2a5af55c0 Mon Sep 17 00:00:00 2001 From: lazydev Date: Thu, 28 Feb 2013 02:43:03 +0400 Subject: [PATCH 0518/1483] fix for https://bugs.openmw.org/issues/573 --- components/esm/esmreader.hpp | 16 ++++++++-------- components/esm/loadappa.cpp | 27 +++++++++++++++++++++------ components/esm/loadappa.hpp | 6 ++++-- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 45d6d9164c..ae876edf8b 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -37,14 +37,14 @@ public: *************************************************************************/ int getVer() const { return mCtx.header.version; } - float getFVer() { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } - int getSpecial() { return mSpf; } - int getType() { return mCtx.header.type; } - const std::string getAuthor() { return mCtx.header.author.toString(); } - const std::string getDesc() { return mCtx.header.desc.toString(); } + float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } + int getSpecial() const { return mSpf; } + int getType() const { return mCtx.header.type; } + const std::string getAuthor() const { return mCtx.header.author.toString(); } + const std::string getDesc() const { return mCtx.header.desc.toString(); } const SaveData &getSaveData() const { return mSaveData; } - const MasterList &getMasters() { return mMasters; } - const NAME &retSubName() { return mCtx.subName; } + const MasterList &getMasters() const { return mMasters; } + const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } /************************************************************************* @@ -85,7 +85,7 @@ public: int mIdx; void setIndex(const int index) {mIdx = index; mCtx.index = index;} const int getIndex() {return mIdx;} - + void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} std::vector *getGlobalReaderList() {return mGlobalReaderList;} diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index f5e7e10e1a..80922e2cbe 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -7,13 +7,28 @@ namespace ESM { void Apparatus::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); - esm.getHNT(mData, "AADT", 16); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNString("ITEX"); + // we will not treat duplicated subrecords as errors here + while (esm.hasMoreSubs()) + { + esm.getSubName(); + NAME subName = esm.retSubName(); + + if (subName == "MODL") + mModel = esm.getHString(); + else if (subName == "FNAM") + mName = esm.getHString(); + else if (subName == "AADT") + esm.getHT(mData); + else if (subName == "SCRI") + mScript = esm.getHString(); + else if (subName == "ITEX") + mIcon = esm.getHString(); + else + esm.fail("wrong subrecord type " + subName.toString() + " for APPA record"); + } } -void Apparatus::save(ESMWriter &esm) + +void Apparatus::save(ESMWriter &esm) const { esm.writeHNCString("MODL", mModel); esm.writeHNCString("FNAM", mName); diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 486a559f89..a1daeb1237 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_ESM_APPA_H #define OPENMW_ESM_APPA_H +#include "esmcommon.hpp" #include namespace ESM @@ -13,8 +14,9 @@ class ESMWriter; * Alchemist apparatus */ -struct Apparatus +class Apparatus { +public: enum AppaType { MortarPestle = 0, @@ -35,7 +37,7 @@ struct Apparatus std::string mId, mModel, mIcon, mScript, mName; void load(ESMReader &esm); - void save(ESMWriter &esm); + void save(ESMWriter &esm) const; }; } #endif From d5aa975675c2bacfe91dd7199143b79fa4ac324d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 27 Feb 2013 23:44:20 +0100 Subject: [PATCH 0519/1483] Fix some issues that seem to have appeared in the CMake configuration. --- CMakeLists.txt | 6 +++--- cmake/OpenMWMacros.cmake | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbab836907..4b092e922d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,7 +378,7 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_SOURCE_DIR}/GPL3.txt" "${OpenMW_SOURCE_DIR}/OFL.txt" - "${OpenMW_SOURCE_DIR}/Bitstream Vera License.txt" + "${OpenMW_SOURCE_DIR}/DejaVu Font License.txt" "${OpenMW_SOURCE_DIR}/Daedric Font License.txt" "${OpenMW_BINARY_DIR}/launcher.qss" "${OpenMW_BINARY_DIR}/settings-default.cfg" @@ -389,7 +389,7 @@ if(WIN32) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") SET(CPACK_GENERATOR "NSIS") - SET(CPACK_PACKAGE_NAME "OpenMW ${OPENMW_VERSION}") + SET(CPACK_PACKAGE_NAME "OpenMW") SET(CPACK_PACKAGE_VENDOR "OpenMW.org") SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) @@ -404,7 +404,7 @@ if(WIN32) SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") - SET(CPACK_NSIS_DISPLAY_NAME "OpenMW") + SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index f2382fd8ac..f66dbf2c47 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -2,7 +2,7 @@ macro (add_openmw_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND OPENMW_FILES "${f}") @@ -14,7 +14,7 @@ endmacro (add_openmw_dir) macro (add_component_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND COMPONENT_FILES "${f}") @@ -26,12 +26,12 @@ endmacro (add_component_dir) macro (add_component_qt_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND COMPONENT_FILES "${f}") endforeach (f) -file (GLOB MOC_H ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.hpp") +file (GLOB MOC_H "${dir}/${u}.hpp") foreach (fi ${MOC_H}) list (APPEND COMPONENT_MOC_FILES "${fi}") endforeach (fi) From 0e8ff22d6fabe839380acdb2cde3fd11706ebbab Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 28 Feb 2013 07:20:01 +0400 Subject: [PATCH 0520/1483] Only install binaries which are enabled to be built --- CMakeLists.txt | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbab836907..e8d5f23c75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -657,10 +657,18 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) # Install binaries INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + IF(BUILD_LAUNCHER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_LAUNCHER) + IF(BUILD_ESMTOOL) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_ESMTOOL) + IF(BUILD_MWINIIMPORTER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_MWINIIMPORTER) + IF(BUILD_OPENCS) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_OPENCS) # Install icon and .desktop INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}") @@ -674,5 +682,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) # Install resources INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) - INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) + IF(BUILD_LAUNCHER) + INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) + ENDIF(BUILD_LAUNCHER) endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) From 3bd228f71b1dab4f5d454b1a1cb7b2506a94afaa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 11:50:29 +0100 Subject: [PATCH 0521/1483] fix for global variables of type short --- components/esm/loadglob.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 429c6ff1d2..9e20578ce4 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -20,6 +20,14 @@ void Global::load(ESMReader &esm) // Note: Both floats and longs are represented as floats. esm.getHNT(mValue, "FLTV"); + + if (mType==VT_Short) + { + if (mValue!=mValue) + mValue = 0; // nan + else + mValue = static_cast (mValue); + } } void Global::save(ESMWriter &esm) From f75681d89b3d29cf1561f0a261829f8b8ad6d347 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 12:12:51 +0100 Subject: [PATCH 0522/1483] Ignore ESX header version --- components/esm/esmreader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index eca0d78548..41a2f738af 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -77,8 +77,9 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) // Get the header getHNT(mCtx.header, "HEDR", 300); - if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) - fail("Unsupported file format version"); + // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. + //if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) + //fail("Unsupported file format version"); while (isNextSub("MAST")) { From 6683e43efcfefffc069fa172b2e0cdd15bb04891 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 12:35:18 +0100 Subject: [PATCH 0523/1483] Removed commented code --- components/esm/esmreader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 41a2f738af..b4f581d7e8 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -78,8 +78,6 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) getHNT(mCtx.header, "HEDR", 300); // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. - //if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) - //fail("Unsupported file format version"); while (isNextSub("MAST")) { From ffd96c771593bc85205e53c487adebf4bdcaf41e Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 13:19:05 +0100 Subject: [PATCH 0524/1483] Removed "Unloading Cell..." text from loading screen OpenMW unloads the cell so fast, it's hardly noticable. This commit gets rid of the "flicker" every time a cell loads. --- apps/openmw/mwworld/scene.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index fb7653401f..99c1793fe2 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -75,7 +75,7 @@ namespace MWWorld { std::cout << "Unloading cell\n"; ListHandles functor; - + (*iter)->forEach(functor); { // silence annoying g++ warning @@ -217,7 +217,7 @@ namespace MWWorld } } - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); + //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; } @@ -360,7 +360,7 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); + //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; From d4aa33b9a7da71682e9afa0cea01b65f9ce57453 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 15:58:03 +0100 Subject: [PATCH 0525/1483] Removing the unloading cells part instead of just commenting them. --- apps/openmw/mwworld/scene.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 99c1793fe2..c15baf43ba 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -75,7 +75,7 @@ namespace MWWorld { std::cout << "Unloading cell\n"; ListHandles functor; - + (*iter)->forEach(functor); { // silence annoying g++ warning @@ -217,7 +217,6 @@ namespace MWWorld } } - //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; } @@ -360,7 +359,6 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; From a6fb58bc59598f77c2ccc415b47ce475b7cf073a Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 16:31:24 +0100 Subject: [PATCH 0526/1483] Using "Loading Exterior" and "Loading Interior" instead of "Loading Cell" This commit replaces the default "Loading Cell" text with "Loading Interior" and "Loading Exterior" --- apps/openmw/mwworld/scene.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c15baf43ba..1e8f6d339b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -27,13 +27,10 @@ namespace { const MWWorld::Class& class_ = MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); - - size_t numRefs = cellRefList.mList.size(); int current = 0; for (typename T::List::iterator it = cellRefList.mList.begin(); it != cellRefList.mList.end(); it++) { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; if (it->mData.getCount() || it->mData.isEnabled()) @@ -55,10 +52,6 @@ namespace } } } - else - { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, 0, 1); - } } } @@ -216,7 +209,6 @@ namespace MWWorld continue; } } - unloadCell (active++); ++current; } @@ -265,7 +257,9 @@ namespace MWWorld { CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, current, numLoad); + //Loading Exterior loading text + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Exterior", 0, current, numLoad); + loadCell (cell); ++current; } @@ -359,7 +353,6 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - unloadCell (active++); ++current; } @@ -367,7 +360,9 @@ namespace MWWorld // Load cell. std::cout << "cellName: " << cell->mCell->mName << std::endl; - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, 0, 1); + //Loading Interior loading text + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Interior", 0, 0, 1); + loadCell (cell); mCurrentCell = cell; From f66f67eaa12f0fcddbb615648b478c2215c77d96 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 17:54:42 +0100 Subject: [PATCH 0527/1483] Loading text uses now the corresponding GMSTs --- apps/openmw/mwworld/scene.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1e8f6d339b..ecf783d6c4 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -169,12 +169,18 @@ namespace MWWorld void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) { Nif::NIFFile::CacheLock cachelock; + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); mRendering.preCellChange(mCurrentCell); // remove active MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + std::string loadingExteriorText; + + loadingExteriorText = gmst.find ("sLoadingMessage3")->getString(); + CellStoreCollection::iterator active = mActiveCells.begin(); // get the number of cells to unload @@ -258,7 +264,7 @@ namespace MWWorld CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); //Loading Exterior loading text - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Exterior", 0, current, numLoad); + MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingExteriorText, 0, current, numLoad); loadCell (cell); ++current; @@ -318,6 +324,13 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { + + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string loadingInteriorText; + loadingInteriorText = gmst.find ("sLoadingMessage2")->getString(); + CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); bool loadcell = (mCurrentCell == NULL); if(!loadcell) @@ -361,7 +374,7 @@ namespace MWWorld std::cout << "cellName: " << cell->mCell->mName << std::endl; //Loading Interior loading text - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Interior", 0, 0, 1); + MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingInteriorText, 0, 0, 1); loadCell (cell); From bd597f07ab85d667ced3c6ef4afce828db73705e Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:22:10 +0100 Subject: [PATCH 0528/1483] Centered the loading text --- files/mygui/openmw_loading_screen.layout | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 4b6861151a..1e4bba5ed8 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,7 +8,8 @@ - + + From c9a701cfa1cf0c4de63717357673c9044b1ae6f3 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:25:18 +0100 Subject: [PATCH 0529/1483] Removed the 3 dots after the load text. --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index dd5289edb1..e7c7acb533 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -106,7 +106,7 @@ namespace MWGui float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading); assert(progress <= 1 && progress >= 0); - mLoadingText->setCaption(stage + "... "); + mLoadingText->setCaption(stage); mProgressBar->setProgressPosition (static_cast(progress * 1000)); static float loadingScreenFps = 30.f; From 06e077c07ca699fb50f1b3d965394291eb1ccdde Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:36:10 +0100 Subject: [PATCH 0530/1483] Removing all traces of "Open Morrowind". pvdk said it was ok to remove the header entirely --- components/files/fixedpath.hpp | 22 ---------------------- components/files/linuxpath.cpp | 22 ---------------------- components/files/linuxpath.hpp | 22 ---------------------- components/files/macospath.cpp | 22 ---------------------- components/files/macospath.hpp | 22 ---------------------- components/files/ogreplugin.hpp | 22 ---------------------- components/files/windowspath.hpp | 22 ---------------------- 7 files changed, 154 deletions(-) diff --git a/components/files/fixedpath.hpp b/components/files/fixedpath.hpp index dce4f96c20..a309dc9fb6 100644 --- a/components/files/fixedpath.hpp +++ b/components/files/fixedpath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/fixedpath.hpp */ - #ifndef COMPONENTS_FILES_FIXEDPATH_HPP #define COMPONENTS_FILES_FIXEDPATH_HPP diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index 0f08b67feb..c974a91d35 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/linuxpath.cpp */ - #include "linuxpath.hpp" #if defined(__linux__) || defined(__FreeBSD__) diff --git a/components/files/linuxpath.hpp b/components/files/linuxpath.hpp index 09acd2be7f..6acf2a2d5f 100644 --- a/components/files/linuxpath.hpp +++ b/components/files/linuxpath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/linuxpath.hpp */ - #ifndef COMPONENTS_FILES_LINUXPATH_H #define COMPONENTS_FILES_LINUXPATH_H diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 9625612ad4..9edcd6ef2a 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/macospath.cpp */ - #include "macospath.hpp" #if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__) diff --git a/components/files/macospath.hpp b/components/files/macospath.hpp index 591c978aa7..576ec16812 100644 --- a/components/files/macospath.hpp +++ b/components/files/macospath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/macospath.hpp */ - #ifndef COMPONENTS_FILES_MACOSPATH_H #define COMPONENTS_FILES_MACOSPATH_H diff --git a/components/files/ogreplugin.hpp b/components/files/ogreplugin.hpp index 2d56bfb47a..6fcf613768 100644 --- a/components/files/ogreplugin.hpp +++ b/components/files/ogreplugin.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/ogreplugin.hpp */ - #ifndef COMPONENTS_FILES_OGREPLUGIN_H #define COMPONENTS_FILES_OGREPLUGIN_H diff --git a/components/files/windowspath.hpp b/components/files/windowspath.hpp index 7fe8bc9559..6044b67c21 100644 --- a/components/files/windowspath.hpp +++ b/components/files/windowspath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/windowspath.hpp */ - #ifndef COMPONENTS_FILES_WINDOWSPATH_HPP #define COMPONENTS_FILES_WINDOWSPATH_HPP From 3df34fb5ccbb8ec0f1870b7f9072ff6576a22dd9 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Thu, 28 Feb 2013 19:52:32 +0100 Subject: [PATCH 0531/1483] fix bug 574 --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4a79f77b85..2b943c50f5 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -274,13 +274,11 @@ namespace MWInput if (actionIsActive(A_MoveLeft)) { triedToMove = true; - mPlayer.setAutoMove (false); mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { triedToMove = true; - mPlayer.setAutoMove (false); mPlayer.setLeftRight (1); } else From f77ace088537a7a999decf39485affe7cb8d0080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Thu, 28 Feb 2013 20:16:46 +0100 Subject: [PATCH 0532/1483] Removed the "hack" mygui.png and misc fixes for this. --- files/mygui/CMakeLists.txt | 1 - files/mygui/mwgui.png | Bin 13534 -> 0 bytes .../openmw_chargen_class_description.layout | 3 + files/mygui/openmw_chargen_race.layout | 45 +- files/mygui/openmw_dialogue_window.layout | 6 +- files/mygui/openmw_edit.skin.xml | 57 ++- files/mygui/openmw_edit_effect.layout | 8 +- files/mygui/openmw_hud_box.skin.xml | 75 +--- files/mygui/openmw_list.skin.xml | 415 +++++++----------- files/mygui/openmw_loading_screen.layout | 3 +- files/mygui/openmw_map_window_skin.xml | 2 +- files/mygui/openmw_scroll_skin.xml | 6 +- files/mygui/openmw_settings_window.layout | 26 +- 13 files changed, 250 insertions(+), 397 deletions(-) delete mode 100644 files/mygui/mwgui.png diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index e7e5b695e1..beace5b81e 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -9,7 +9,6 @@ set(MYGUI_FILES core.skin core.xml EBGaramond-Regular.ttf - mwgui.png Obliviontt.zip openmw_alchemy_window.layout openmw_book.layout diff --git a/files/mygui/mwgui.png b/files/mygui/mwgui.png deleted file mode 100644 index 318f16e41873af708fd31d302bf0726efbdf916c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13534 zcmcI~3shQnzAi~>Y@3H?&P-zyQ|+`i^dvT>8iR^T)6>M7hccU&Wh ze;|(|x-aTFb%k1H@W@E$uzzS#PhD}(&pw~s`W$k=?Yj@}zH#?X#}}V}5%T{0n|W`# z{qDrwH;#UFb^y#IUB@4tWJ4^RBOw|dOp-1lVZ1-7yC&pFYw=AW<#b0^+2 zUy+?7a9KII_#n_=`m#yetkPiwwTv`A(^f!#d{%A9e-8pdzI!EcGvu24Nh6#zcQ4Vz z%2+g;48FFk&LvjVw8m8@U(#Nc=I53*C}E;;F|TXoLgzxcQ12R6P(`iOCbw#pb8Ovx z##!ZM-NyrqK1S{w&#TJobe-i%#y`__2F{9ZR&863O*G~#E+cI&B6V1Y49>_vQb=S2 zIXk{7Au4uv$<`otT{0nbKw>TNs?z1`LL8#}hq|DUZi8Ev<8lhAoK7LBE74ZE0w)EM z6aw2wg7nm*AKXoEO`dNn&&fB%b8)g*7sv`ptF!TJeq3X?&h&Z59W-J~AoVo)0pS>A z(q&TFxw*=l)!y+Xb86dWi0@{E@tr5$eTI>o)*FS1zk}p%T4K>5`yztX(d{eIfHmJF zY7bnCD5Ex=xqlM%`IaZePXvW7ha$3!e4^r{*H)Kn?$>GNx6hX)jp^e|5C@FLdA+ z$oenC$Fd4T4exBa=6-E$lIikNPT4lWH=8E^vc3@&{zj^?_RXF4jToESMdQ-h)dzr8 z`99KWxNmJonTl-&+JL|&M^Jr<+TZ7yy9$Cj3u>93b<--->DEOY_93atw@_}dTo-tz zDDM?iH<|M+TDI!JXwW#kza@0QiXrG-72#y)Mwf6`MuebK8ZqY-RD4vx5AJ_X=OF3i zX)=9pNnkMAFsjI=%yW%u?etZAr!@VMd z&y+e&tHoHJ5a^7h>mqNYOkH4=y%Y+5Qmbcxz}vR6Oy`=A2b-07%D%rGS@^*HGr&XJ zZ$Vrkxm^>)t+OY&^H`B|Y*5Humha8@h*E!n?+X=4!~^keQCayx{7kGrUMJKJhu8g`o=+RmrhwjnA>%gaTw(IDF^+e&(#L0&|VpR{>L(L#BvN%5=tBYi54xj3&* zB!zNH&g^v4-F;k(dag}Ep`c{Zv1cf#sfc9Zo+z{YOk0`I*v1g12I4-Fm1OD(D$Fl5 zr*mi1xfkAnKzvg+5td&OSAHWI^?ABEMg|&_a%t>z0cTL2U5;!ZAB6{Tt5bp#QHNin zKBY{1S-UIsA}?EpXQ%P#56hYw{j%Dq$J`iEWoOk~ zz*lt_@hq=Uh)UN|J~w?Oofh0_Ra?7xZlNx3Kyq&bUdepKx~<9(9SVZ6SnvRg7oW2{9>n)jwr-Yp$$SA!y>Vb_L)hx>Pxab$Y+~ELW1|V|Ffc=1;^jQ z2BDD%9g%Tti0%e5t@X*mVmgheb}F$8ztz4OLyEyvcAbhW1M z7gIRo$+iRtEIdB$o$X7Po5imi#2Dh^!EkJ;XGmM&vhh_{5ipQwuK`PFtLB|SltxBk zXq%;Qso-Uo;>uz;!uk?QFe1bFQ{g&<6`rR|Et}qkFw}RNfmA*RiPa|^nmOV*J2a6L z!W%u#ovSTXXy3b%fQbm$P{sUIekP}87vujW;V;P2iarZxco zVF@X1hOP;k^+N>KEEH5enW}WdTIPQMqNStFB{O6<3j1q%$YedMm{OeahmcJcBuf}( zJyABj0`pQ#&$-gn?9Lkba@yh#i6_g*WL+4~av*Uf&6A@i&J`^1BRZGmLhSsj?*M<# z{?cBUjSubYzazFJyed`PFFvNwADar29Wb6GDZOO7x{B3qq_Ekgd%T219%kFiD{m2W zemy;KCdo##+_MeicS9zFn7k|P2}wU+?%cLi&+58dmE5(uXOjLU-s%r6rDNxpf+_Jj zZgdB0gl#p5Ns9lVehYyhdNsd)g61YJOl#{|5(#I!nMd;`9u|5m%vTFI6(mbz;_0$e z_xnU5Zxo8$v8b~8a5ch!y9IdbAC(36)?;E%>H7=D#aK&k>X5*dl)qLaeEuzLe)^iK7ptKg9SzNp!D~E@T z4bH8k+$xpITnL0m)nuqw$nOX$soAvZ3Np>|H($c5&n^Sw4FM}};+@H-DqLpSS$c|3 zj9OtkP5exI$qUXO9v+zSx;a1IV8r5^iZanOZ_TrU9(UPMx?@Su|LkVVYH_r}Rk3N#d zA?=vx3rAZ5O^fG#k>%~Fn#Q@#;_Kd!O1IAcZOYPzF!;wn0N1h#H@DR$pyIxo2&@V6=7k0PY`>N922^S{koe_?XSnx+dl985o}At%%(l4LAd(2U9SuQVM=RfhGRL>6r_1U zml~q1XT>IRDq%8W?drF8p1eG^4CA$9ss8|d8jjh4&`D3iy_T_M1j7JbwhQPjbqB6Z zCI4ymcTaTvg_a-5wpW4`v&n;`5h%2gz8>{Q|Bv0J=xH=@=HGnfG{Ds>eF!U09As1b z5<_jTxhpsH#Uyj3{$8S)w|%QM<5qC$ZP_GU;&ZXNv1_VOII>EPsx3AX{jx!8IBu=vvXPVD>HWn%O7O%P=7<~Bw^ ze}>57f9)R2>%MO04PxgTMCG^t1f**##PhwGlrx#{dTv?}Sue_Me- zTn_bJ3_HmjCisV^Hh-%Nak1P>%nm#ZY^^Cr5pNCBT z<&$gr=mRj=@Utx^umOcH8;A?75WqeUU1qf>@z|g`nCDkD<_luP#9%rNKsP!@L}%f@ z_SQpJ%K>0&4Ug(G$`j}h@T?DuW%@{I-trHKEs&1Cx?~1KecO$k+5~K@0KMo=1Z`UDo?Ly~iC_rygsE_Pcl&<|}^PGxBm z1XwE8{KjlPq5LS*lt)~1$X<(Oyy2E!B;eGnR#NW>PtMfwe*z%*!E3|v4~mcJrxJio zO#rj*n<^&A2l@mnw`r`xe|{4(`}r=QPtZ(+A;M=Dv^V7LL<6i-M^daleJtB7)r^kf zmR<166$%LC#{>wIdE|xqh;P=aRrk9;L87S9H8f>x%@)X=tW60~n3jY9udnP^(u9=9 zX)E6J!>*9ep9+|H5 z?Y9%T)Tb?`arYOKM0rQ@c>?Ue@HRodVnLcK zinHOo;)K+lkZb)wSj-Xk4Jg=oCjs92XTZ>=4}gF>AUUyqi9rx*41^&d-q!E7{1zMs zlkwu$mpFqHr#`MBRoIQw#^hEu&UMUPvrpVLbf)J@jhVEWD{sO%cgI*shGbld! z(NMa>a=D?M{AYLaZXZ}(BpVWmexW{0I$*bB+t+kIN&wT7L^@lab@3LM6-djp8>mSPW`?{gh=q7Ac6b^&)p_B?JHN-#>+qYN_+hdQ?!gc%F(O zXw)VPDy#x8E37E0ukSERQ#}!^-t$<0*YF-uZP);x+I^Qx?a_tyT@2}aslBjVA1NhF z5fAz{&ri_`1C;KuqKWZ7ll-)22(dz&Syf;}@?#T8a5|c<`)i6H8$?e z&?H|QsgoNEUtUVpP4uar1~v%l zQcw?XOE{7a?xWB?$rm z?2@;SQ}=4$OKEB2!!ew4fo-f2;J4(7piVMON~~oxMzp#uVuAWUv=Gsnm>)Ep?5pcE z2TF3X+VI~e7gU&KODScRZNeuy+XDI)GS9>cI3yU-4r%r*O_X*36AbIPTW{?w>*Bkn zpI5$bEztshv6L2uR8|U^>60&~P^u8-*05GqKPpWBv)kwsdGyX!#MfJTTuSk>;jk_#J~i zm3eaMOU<4(+vwE9V64}J>xP^ow-P(gZJ}^3>|6}{dJ7vKZ~7H_3nP4DWqK*ILb&I) za19jMpx5$uzoBhl%J9G(u=sgzu@QKZnv=CKvFB^L(Da>vG>_X6 zlDpuoqar2E*8v3}-Bd`En$GX2?Wi%8B1*-% z8G)$@A^ai!OKke2AI-Wx}r{~iux-Nf@;TQsk zld~)@Bnc9q`DyA6ldyAXE_+csZAq(Wh>{M(kiNHaIJL+y-iT_rWAU}5HiXs7mm)h2 ziu#18N)Z?PJ;3viRJe;e%vsIP8as^Ah~re`&P6wDD5p1Gmj9uLN0H@KLn6NjUnhUX zzo6wB0+m9>jHecrj)mG5Xoa7UUiIiwvX%EvRZ>HUM#;j9{vqiZMfG$EhN%8mu0ZA# z;Z{~I94A9X9P^(PO-DVs1!bcbtLr)SciDp;vgMc*Mjr7uJ#7$PTBqPs>qCO`D)2O9 zN*kw~-GkTPvnf4HeX+3l7mdEC5lR0P+1OHb3JVk(?T=Ip(duEkExd(Yp7Dbh6a_Z9afCy@6faWbNc8dctuLkilFHPZg zOt1=S)pPTS`8$9LcMN9)GNT~;hDbKCbbiOF(LCL>1i0CsJxGyt*e3Sm*3`qpnLwUp zBE(*2x8VKH;ee@MCEQf9+G`bj{-Gk?g;sN)JgNFo z@a~-WAZ}e!>*af5K&y;v5T?pgTKY4`1S8qi#l;ajTW_fFV%36KDcUtBP3J_sJ1wH3p1$Pg~t5SmH|8p3BAp(e75#<@EFAF?EHPcVxE&y_Pm#KSL)!)u-QK z^D~ya_I%wePQ?QOa>JFfdwag^Mfx3~POf@7%?kMI_Txp$(a)d~!?L;gI>i*+E$a$+ zuFdw#NAJkEV(=?K@0d6hyE}}z^%m~i)vwVeBlm_3vjf<{gymYm!>^ePk$G`XRnssA zYQ2Dn@5b$8Br6(?+#VP?u6f@8p#Svc-o%LQQ2X1_SEh;Ilha z`NitF->fnvLlojpmfsNeUZmzUQXj$daAEvA625fweKij5;lX(nQw;Q_3v{yK;_YE| zUOor?tu^NUa74aj)RikNkc4om?s5{8{H~PcZe)I(BC8#cVpi2ZMq}LB)O*5nz`bW1 zWA+v2EEf?YeW7vuiXf@DcYojcdfJ(Sa(&-^4jO8GpkGL=V{ z^0YszT6wRiB>RTUYPN_*yaz^%$Pbk;eL~`CYzOQFd*lQ@uop+77WerzVQgUtc1=?2 zm#xg@>eJBF$DKx-%nQB4Z(>h!!R$*Lo!e2J5)##}Np6=RKb%tSw-OOkPxqsgQ!`f< z{9ogTUmIIOGf=_tDWgEYs4HR2S@wK=(7z7B-MUNlD2u&yS8+~^py@i1U2bgxdf8=q z*izxj%ATrwLUo}GC>j^bMzQI4XvqhO&-Z-I^s6R4+`4NxS*ryG7!9KN0Ey3NOdSPA zh-@(Ypqo;S_>d_gpbFTgVmp6`wxS7}b8{b3d?(iIKT*bPAnN9~(=iFx~C_#2Z)R&Yb zNh~Lr_JI}`Be!y#e9fa9Iqni_-`p5dz(@$-{%R*if!yGzh*G;NZUO9a|JZ=teznXS zfY?W>T4QdS&12&Jv~yoUwym2UHXJdUx`JFIYU3`mul=l%dI#a1Gn_u+$^i`&cW_vp zLy208ZYJc`R*BEsd_X){vzAtePHxTUtagyphg@=W*LRLcc@V2A-@DGa(VIdFaTO&* z{XRPdpLo~Mf(`(qwWx@C(;cMAv@mvW*3hb$vQ9}~P7Oa$=)o1m!{My9x&Q}_3jvO; zD5-ikz1`sjnxo?qr}^}%59-g*LB?uW3ic>MgY2H73Y5fvTTdRX=GR~p_DtRx?$Ouo zWcE~zX8YSXN1(%wTOYx}6^qq*6^%LiO@CR}3=Gph{pethbb)UR5{3}mTaV5q12bw^ z9l&)E`=wdJ?MSAn#M4e~E0OJF)q_>NWPPYoE}=>U9F#axH<*%iF0^B3hYyH+KA&7zVN{IsBZZ}ML5mMpeQ9@qS~B9-3#L)ymP_RD!0Ug|K@sN-dExdo*{43tEsqU=ib|=pSth z>vx2~*t^L;p9L9tNMP{bQ^NyrBCV9T&jm~qY7R_7Yykh5?KhzKaaA*150W%O`57*l zZ<&6y`;XC}Ow)#D`cnhA!wx;+=bx)_jnjLdw5*pC{vvLx1P2Di%RA(lqmHaf3HpS+ zu0u#R2f`7j`%PTvF#agF%&DbF>TXSnN~NvEv-)7A4dYpSRHq_DI*xWTdoQ4zri8rB`!|2OAoV zE|d)rHc$b}&CISUR;R8nG0pu+clW7XYkJ~ZNx+Rtvdui5Lyd`S&}VEf081zx)7-K_ z0NX2orY1X^lq4^!~JV0Vk&8d;8>~fc78mde7ivx9@4(vm!sl%>W zu^`BEiT6g%f|aMEqpkO$(83_tou$exD>=$^1n7CFI(tLC2rn9R8r;(}1J#)Uc0z!; z1C<8!)skXgH`>`4V=H5KFN}jWbX#QlCBjH$&J;@V!#I66?K5EdcgGqgr^v$(DxH|2 zQSJxWRN&~1%vK;RoI{0lV5^ELabWOink0jY#(hEob;GgOI6&TW=HFuu71;%M$a&Nz-U8d{S}Xd1`Wr_AjAYcx z+w;op4JXn!l5y7AHu`ewfDA;L?71`06pnr*C5qb{ zYZ$0L22xG|x-7Vtnbxuxwi6zWK6{^$tk+xYvxK|C;~qG>1R8V2+a=afW9jr}|Cs=U zz^<3(VzJbt%*l7F?6_sYm7XI zcA^m@&gdV1#O9N@o-T(5aLYw#{adS{_u(-riHiB*^U;Uaphj(b4QmbLT+%4fl#)=HO=UQj0C6RPB!viqy>P>n`L?? z+(oebP6EPJL~DQLrsUlR08sO@HpLBsQs$%3a>cPjq);-5v~8g zo_87e;OapN2o}O}m8mhnsktL=8w3X#$N+HYjK^ib4!{iOOCz5RD=>1q*6&t&E9Bpwql%9?k>Gx2az^7e)Z!o(zh&|ZJ3E@3wj5S}ZDnNkb1~A2|+Ta*4RxB^&Swcow&g3|7zI8l4?>9|3I`8BM1nufq9m!uuqcw=pj^2`6m{Y!?zfEQx5&S3v zPe{xXTuiDHaIrbJQ@cP^TVF)=*>=!i=iWP)IoW5O3|SB+FsHkUDx?^UZpi z0lcA;QK@QiW=?izZ?@FQmBenelu)M~L%3~`qfP+Kmf+4dDZqmwt(WI?RtT78xtY0D z8xOPYz)my{JNaBzYyah6LGP~fIXm1Ocgf5mBO9Eny2$Cz7zH!yJn2wxn#j3GJ|7Jb zIxyQ|;YHbRhYi^4$jqZ%al0lQ03=~z^)S+5@jzDFmwiQ!Q@-pGUe<_RnE)Nd@t=h0Tm&!ZJyaTC_uN{rX79Rsv<6z5yuX0*W={-X2 z&CLw|`=kTZlw@bpAseWX8;%`Ss<@b;lzgGbu4rqJ)>8S>1WBgAwl>EHg8#NTBXYKvr zE5tikI~^&3k{9xw*xYy?p+BZ)X4$n4TD~EW9N{#3qrne=?ivS=V=x#C!62jR5dtDn zHYgG`yBBX?cEkjxfw62Js1_9es8lDI@-UtDDPR?QISobpAPjEsmGk3CsVLgpz|T z2LcyFaJfe!8m2)g)lz;cg$Kjh{Tg0>=Bzpzj2DfDx;@`%BiOf`N89opY7wUn6_?rI zXqm(uWOjo?pdwtYj_yJ_*j9&sf7Xbl+X3(6F#Z6?cl7_gQBW}9fHp#D99VGb0jnyGxv+Nx0(n=M~Afz`oN8r1)EWP^mFCGIPBatuul zltXMVIdoJ&LwWZ9NJG)`ao=tb7>;tuWy)MTrSRDoS7C>QObGuV|4%Qb?EPj+eKn>L z+<5Uy%&tZSNTyJl3!~~7FsbLJ_eJQ9juIMM=?=)>h&~51#O&LcajlFK4a5KP?pGCS zwQgds!9N~&yTrlD+PGv>3)nifnv4{VQ!5IjM*6>U27gB&xA#XO+L0PCYsK75?ffN;JWv={xJ zQlDt~Zk^@)I&_vURC}9vq$OF>sJP!MTW*?=sFE)o?lsB1*#!l8>X#9bzCF9qXoXh7 zHa+vur95owFD-n1&yvU`meI@yNFUl}(%lLJHbIE6cb-IbW>txJhiUCha(9tt`?BVd za3CQvR+SUH`w>}BNxiSnIbKi9r$$E#F!Qq_Z;kZhMAFoIiKijgWT#zL-=`}&N!SGW z1MoiNKl%ZlhWr;kpKW>rc=!7s`+NlfG^zi>=O5kD>iz$PEv-KDk8a6v|Hf@CoqKI_ Zfjvhb*ux%p4FUc|9E<#-`SbJN{0~$*&Ncu5 diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 11031eb4e6..8823e1e760 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,6 +4,9 @@ + + + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index a9ec9905da..4ef8da0f3f 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -8,33 +8,52 @@ - + - + - - + + + + + + + + + - - - + + + + + + + + + - - - + + + + + + + + + - + @@ -42,11 +61,11 @@ - + - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index 1271a287b6..9a9da72d4c 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -3,13 +3,15 @@ + + - + - + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index 02fee4b179..da21385e2a 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -1,55 +1,52 @@ + + + + + + - - - - + - - - - - - - - - - - - + + + + + + + + + + + + + - + + + + - - - - - - - - - - - - - + + + diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 45ecb63edf..cad22c064a 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -31,7 +31,7 @@ - + @@ -39,7 +39,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 464b6343aa..23480e8d35 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -1,80 +1,31 @@ + - - - - - - - - + - - - - - - - + + + - - - - - - - - - - - - - - - - + + - - - - - - - - - + - - - - - - - + - - - - - - - - - - - - - - - + + + + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 64435451ad..6631424ccf 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -1,228 +1,107 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + + + @@ -234,81 +113,85 @@ - - - - + + + + - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - + - + - - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 1e4bba5ed8..4b6861151a 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,8 +8,7 @@ - - + diff --git a/files/mygui/openmw_map_window_skin.xml b/files/mygui/openmw_map_window_skin.xml index 0c6050969d..13f18c6d3c 100644 --- a/files/mygui/openmw_map_window_skin.xml +++ b/files/mygui/openmw_map_window_skin.xml @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index 70fad3f4b4..1b94f0c291 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -2,12 +2,12 @@ - + - + - + diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2f9b5a67f1..8d435bfd53 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -15,7 +15,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -64,35 +64,35 @@ - + - + - + - + - + @@ -117,7 +117,7 @@ - + @@ -133,7 +133,7 @@ - + @@ -192,7 +192,7 @@ - + @@ -208,7 +208,7 @@ - + @@ -233,7 +233,7 @@ - + @@ -241,7 +241,7 @@ - + From 3efbb5e728b5708ee738279ccbe15ed765efadf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 20:27:35 +0100 Subject: [PATCH 0533/1483] Don't try to render a map in empty cells --- apps/openmw/mwrender/localmap.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 601ee58e31..1a14b86bfb 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -119,6 +119,10 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, AxisAlignedBox bounds) { + // if we're in an empty cell, don't bother rendering anything + if (bounds.isNull ()) + return; + mInterior = true; mBounds = bounds; From 0b629791a82cc2abcaa7b1c2b106a81763c56a57 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 20:40:32 +0100 Subject: [PATCH 0534/1483] reverting loading bar layout --- files/mygui/openmw_loading_screen.layout | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 4b6861151a..1e4bba5ed8 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,7 +8,8 @@ - + + From b7ab12e7cf4e919cdd664254163bf8c204be2771 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 21:12:13 +0100 Subject: [PATCH 0535/1483] Workaround to prevent the map drawing on top of the world button --- apps/openmw/mwgui/map_window.cpp | 19 +++++++++++++++++++ apps/openmw/mwgui/map_window.hpp | 3 +++ 2 files changed, 22 insertions(+) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 6f7f0eaabc..52b108f850 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -13,6 +15,8 @@ #include "../mwrender/globalmap.hpp" +#include "widgets.hpp" + using namespace MWGui; LocalMapBase::LocalMapBase() @@ -96,6 +100,7 @@ void LocalMapBase::applyFogOfWar() : ""); } } + notifyMapChanged (); } void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) @@ -425,3 +430,17 @@ void MapWindow::notifyPlayerUpdate () { globalMapUpdatePlayer (); } + +void MapWindow::notifyMapChanged () +{ + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); +} diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index 4e2dd67567..39770a7a26 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -50,6 +50,7 @@ namespace MWGui void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); virtual void notifyPlayerUpdate() {} + virtual void notifyMapChanged() {} OEngine::GUI::Layout* mLayout; @@ -99,6 +100,8 @@ namespace MWGui virtual void onPinToggled(); virtual void notifyPlayerUpdate(); + virtual void notifyMapChanged(); + }; } #endif From 1168f153611cb7e017c092496f3b31c978cd090e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 12:17:58 -0800 Subject: [PATCH 0536/1483] Don't disable depth writes when blending is enabled --- apps/openmw/mwrender/activatoranimation.cpp | 3 +-- apps/openmw/mwrender/creatureanimation.cpp | 3 +-- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/objects.cpp | 3 +-- components/nifogre/ogre_nif_loader.cpp | 2 -- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 7bc89b9179..a3332d4b5c 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -42,8 +42,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) while (passIt.hasMoreElements() && !transparent) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index b85c4dbbda..3adb0c4489 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -43,8 +43,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) while (passIt.hasMoreElements() && !transparent) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 809e3f6d29..ce15841fc6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -118,7 +118,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index add781459e..9aa65ac995 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -148,8 +148,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e6779ac1af..4d4a0d9c51 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -716,8 +716,6 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String blend_mode += getBlendFactor((alphaFlags>>1)&0xf); blend_mode += " "; blend_mode += getBlendFactor((alphaFlags>>5)&0xf); - - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); } else From 60f22194507c45f235c13928f3d7ca64e1629536 Mon Sep 17 00:00:00 2001 From: lazydev Date: Fri, 1 Mar 2013 00:46:05 +0400 Subject: [PATCH 0537/1483] fixed zini's norices --- components/esm/loadappa.cpp | 2 +- components/esm/loadappa.hpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 80922e2cbe..643fefda51 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -28,7 +28,7 @@ void Apparatus::load(ESMReader &esm) } } -void Apparatus::save(ESMWriter &esm) const +void Apparatus::save(ESMWriter &esm) { esm.writeHNCString("MODL", mModel); esm.writeHNCString("FNAM", mName); diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index a1daeb1237..820c44c592 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -1,7 +1,6 @@ #ifndef OPENMW_ESM_APPA_H #define OPENMW_ESM_APPA_H -#include "esmcommon.hpp" #include namespace ESM @@ -14,7 +13,7 @@ class ESMWriter; * Alchemist apparatus */ -class Apparatus +struct Apparatus { public: enum AppaType @@ -37,7 +36,7 @@ public: std::string mId, mModel, mIcon, mScript, mName; void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void save(ESMWriter &esm); }; } #endif From 230136438b096d017ac490cc65347d73bc2b8854 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 22:17:07 +0100 Subject: [PATCH 0538/1483] minor cleanup --- components/esm/loadappa.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 820c44c592..486a559f89 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -15,7 +15,6 @@ class ESMWriter; struct Apparatus { -public: enum AppaType { MortarPestle = 0, From 2786cc67f61e9e4aa6338222491ec96c501c4f5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 13:38:48 -0800 Subject: [PATCH 0539/1483] Fix loading empty NiTriShapeData records --- components/nif/data.hpp | 16 +++++++--------- components/nif/nif_file.cpp | 5 ++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 63df23b273..46b58da8f9 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -142,20 +142,18 @@ public: { ShapeData::read(nif); - int tris = nif->getUShort(); - if(tris) - { - // We have three times as many vertices as triangles, so this - // is always equal to tris*3. - int cnt = nif->getInt(); - nif->getShorts(triangles, cnt); - } + /*int tris =*/ nif->getUShort(); + + // We have three times as many vertices as triangles, so this + // is always equal to tris*3. + int cnt = nif->getInt(); + nif->getShorts(triangles, cnt); // Read the match list, which lists the vertices that are equal to // vertices. We don't actually need need this for anything, so // just skip it. int verts = nif->getUShort(); - for(int i=0;igetUShort(); diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index ba3a7513b2..6e806e7ecc 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -220,11 +220,10 @@ void NIFFile::parse() for(size_t i = 0;i < recNum;i++) { - std::string rec = getString(); - //cout << i << ": " << rec.toString() << endl; - Record *r = NULL; + std::string rec = getString(); + /* These are all the record types we know how to read. This can be heavily optimized later if needed. For example, a From eaa6813917498b84eb3ea02adb3d2ab3b26e08ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 13:54:53 -0800 Subject: [PATCH 0540/1483] Workaround for meshes without any vertices --- components/nifogre/ogre_nif_loader.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e6779ac1af..a86487854f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -844,9 +844,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Set the bounding box first BoundsFinder bounds; bounds.add(&srcVerts[0][0], srcVerts.size()); - // 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. + if(!bounds.isValid()) + { + float v[3] = { 0.0f, 0.0f, 0.0f }; + bounds.add(&v[0], 1); + } + 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()); From 1d988676febb8b0e6629f6ca9b2eff0bdec6512e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 22:56:29 +0100 Subject: [PATCH 0541/1483] Local map: the obtained bounding box wasn't exactly accurate, getWorldBoundingBox seems to solve this. --- apps/openmw/mwrender/localmap.cpp | 5 ++++- apps/openmw/mwrender/objects.cpp | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 1a14b86bfb..918ec4580d 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -134,7 +134,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mAngle = angle.valueRadians(); mCellCamera->setOrientation(Quaternion::IDENTITY); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, 0, -Math::Sin(angle/2.f))); + mCameraRotNode->setOrientation(Quaternion(Math::Cos(mAngle/2.f), 0, 0, -Math::Sin(mAngle/2.f))); // rotate the cell and merge the rotated corners to the bounding box Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); @@ -156,6 +156,9 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mBounds.merge(Vector3(c3.x, c3.y, 0)); mBounds.merge(Vector3(c4.x, c4.y, 0)); + // apply a little padding + mBounds.scale ((mBounds.getSize ()+Ogre::Vector3(1000,1000,0)) / mBounds.getSize ()); + Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index add781459e..e8ee3f95f5 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -113,12 +113,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; NifOgre::EntityList entities = NifOgre::Loader::createEntities(insert, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) - { - const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); - bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(), - insert->_getDerivedPosition() + tmp.getMaximum()) - ); - } + bounds.merge(entities.mEntities[i]->getWorldBoundingBox(true)); + Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); float size = std::max(std::max(extents.x, extents.y), extents.z); From 2c05a7477cfc37faab23217c87fe7527aa2a9dbf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 17:16:28 -0800 Subject: [PATCH 0542/1483] Improve checks for texture resource names that include the "textures\" prefix --- components/nifogre/ogre_nif_loader.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index a86487854f..85fbfea264 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -605,7 +605,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String */ static const char path[] = "textures\\"; - texName = path + st->filename; + texName = st->filename; + Misc::StringUtils::toLower(texName); + + if(texName.compare(0, sizeof(path)-1, path) != 0) + texName = path + texName; + Ogre::String::size_type pos = texName.rfind('.'); if(pos != Ogre::String::npos && texName.compare(pos, texName.length() - pos, ".dds") != 0) { @@ -616,18 +621,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) // verify, and revert if false (this call succeeds quickly, but fails slowly) if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = path + st->filename; - } - else if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - { - // workaround for Better Heads addon - size_t lastSlash = st->filename.rfind('\\'); - if (lastSlash != std::string::npos && lastSlash + 1 != st->filename.size()) { - texName = path + st->filename.substr(lastSlash + 1); - // workaround for Better Bodies addon - if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = st->filename; - } + texName = path + Misc::StringUtils::lowerCase(texName); } } else warn("Found internal texture, ignoring."); From d8f2d0195af6b9ac35560057412e0afb1544ec58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 18:45:52 +0100 Subject: [PATCH 0543/1483] Got rid of the texture rotation hack by rendering the cursor manually. --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/engine.cpp | 4 - apps/openmw/mwgui/cursor.cpp | 130 +++++++++++++++++++++++++ apps/openmw/mwgui/cursor.hpp | 62 ++++++++++++ apps/openmw/mwgui/cursorreplace.cpp | 16 --- apps/openmw/mwgui/cursorreplace.hpp | 16 --- apps/openmw/mwgui/windowmanagerimp.cpp | 19 +++- apps/openmw/mwgui/windowmanagerimp.hpp | 2 + files/mygui/openmw_pointer.xml | 11 ++- files/mygui/openmw_resources.xml | 21 ---- libs/openengine/gui/manager.cpp | 2 +- 11 files changed, 219 insertions(+), 68 deletions(-) create mode 100644 apps/openmw/mwgui/cursor.cpp create mode 100644 apps/openmw/mwgui/cursor.hpp delete mode 100644 apps/openmw/mwgui/cursorreplace.cpp delete mode 100644 apps/openmw/mwgui/cursorreplace.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b3f4cd57b9..7cfeb84c5e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -26,11 +26,11 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui text_input widgets race class birth review windowmanagerimp console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list + map_window window_pinnable_base tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog trainingwindow travelwindow imagebutton exposedwindow + enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6f59349fd5..d14696cdd6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -18,7 +18,6 @@ #include "mwinput/inputmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp" -#include "mwgui/cursorreplace.hpp" #include "mwscript/scriptmanagerimp.hpp" #include "mwscript/extensions.hpp" @@ -333,9 +332,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) loadBSA(); - // cursor replacer (converts the cursor from the bsa so they can be used by mygui) - MWGui::CursorReplace replacer; - // Create the world mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp new file mode 100644 index 0000000000..852eea29a4 --- /dev/null +++ b/apps/openmw/mwgui/cursor.cpp @@ -0,0 +1,130 @@ +#include "cursor.hpp" + +#include +#include +#include +#include +#include + +#include + + +namespace MWGui +{ + + + ResourceImageSetPointerFix::ResourceImageSetPointerFix() : + mImageSet(nullptr) + { + } + + ResourceImageSetPointerFix::~ResourceImageSetPointerFix() + { + } + + void ResourceImageSetPointerFix::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) + { + Base::deserialization(_node, _version); + + MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator(); + while (info.next("Property")) + { + const std::string& key = info->findAttribute("key"); + const std::string& value = info->findAttribute("value"); + + if (key == "Point") + mPoint = MyGUI::IntPoint::parse(value); + else if (key == "Size") + mSize = MyGUI::IntSize::parse(value); + else if (key == "Rotation") + mRotation = MyGUI::utility::parseInt(value); + else if (key == "Resource") + mImageSet = MyGUI::ResourceManager::getInstance().getByName(value)->castType(); + } + } + + int ResourceImageSetPointerFix::getRotation() + { + return mRotation; + } + + void ResourceImageSetPointerFix::setImage(MyGUI::ImageBox* _image) + { + if (mImageSet != nullptr) + _image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0)); + } + + void ResourceImageSetPointerFix::setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point) + { + _image->setCoord(_point.left - mPoint.left, _point.top - mPoint.top, mSize.width, mSize.height); + } + + MyGUI::ResourceImageSetPtr ResourceImageSetPointerFix:: getImageSet() + { + return mImageSet; + } + + MyGUI::IntPoint ResourceImageSetPointerFix::getHotSpot() + { + return mPoint; + } + + MyGUI::IntSize ResourceImageSetPointerFix::getSize() + { + return mSize; + } + + // ---------------------------------------------------------------------------------------- + + Cursor::Cursor() + { + // hide mygui's pointer since we're rendering it ourselves (because mygui's pointer doesn't support rotation) + MyGUI::PointerManager::getInstance().setVisible(false); + + MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &Cursor::onCursorChange); + + mWidget = MyGUI::Gui::getInstance().createWidget("RotatingSkin",0,0,0,0,MyGUI::Align::Default,"Pointer",""); + + onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); + } + + Cursor::~Cursor() + { + } + + void Cursor::onCursorChange(const std::string &name) + { + ResourceImageSetPointerFix* imgSetPtr = dynamic_cast( + MyGUI::PointerManager::getInstance().getByName(name)); + assert(imgSetPtr != NULL); + + MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet(); + + std::string texture = imgSet->getIndexInfo(0,0).texture; + + mSize = imgSetPtr->getSize(); + mHotSpot = imgSetPtr->getHotSpot(); + + int rotation = imgSetPtr->getRotation(); + + mWidget->setImageTexture(texture); + MyGUI::ISubWidget* main = mWidget->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + rotatingSubskin->setAngle(Ogre::Degree(rotation).valueRadians()); + } + + void Cursor::update() + { + MyGUI::IntPoint position = MyGUI::InputManager::getInstance().getMousePosition(); + + mWidget->setPosition(position - mHotSpot); + mWidget->setSize(mSize); + } + + void Cursor::setVisible(bool visible) + { + mWidget->setVisible(visible); + } + +} diff --git a/apps/openmw/mwgui/cursor.hpp b/apps/openmw/mwgui/cursor.hpp new file mode 100644 index 0000000000..3a4a05f4ca --- /dev/null +++ b/apps/openmw/mwgui/cursor.hpp @@ -0,0 +1,62 @@ +#ifndef MWGUI_CURSOR_H +#define MWGUI_CURSOR_H + +#include +#include +#include + +namespace MWGui +{ + + /// \brief Allows us to get the members of + /// ResourceImageSetPointer that we need. + /// \example MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + /// MyGUI::ResourceManager::getInstance().load("core.xml"); + class ResourceImageSetPointerFix : + public MyGUI::IPointer + { + MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix ) + + public: + ResourceImageSetPointerFix(); + virtual ~ResourceImageSetPointerFix(); + + virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version); + + virtual void setImage(MyGUI::ImageBox* _image); + virtual void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point); + + //and now for the whole point of this class, allow us to get + //the hot spot, the image and the size of the cursor. + virtual MyGUI::ResourceImageSetPtr getImageSet(); + virtual MyGUI::IntPoint getHotSpot(); + virtual MyGUI::IntSize getSize(); + virtual int getRotation(); + + private: + MyGUI::IntPoint mPoint; + MyGUI::IntSize mSize; + MyGUI::ResourceImageSetPtr mImageSet; + int mRotation; // rotation in degrees + }; + + class Cursor + { + public: + Cursor(); + ~Cursor(); + void update (); + + void setVisible (bool visible); + + void onCursorChange (const std::string& name); + + private: + MyGUI::ImageBox* mWidget; + + MyGUI::IntSize mSize; + MyGUI::IntPoint mHotSpot; + }; +} + +#endif diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp deleted file mode 100644 index 2079538fc2..0000000000 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "cursorreplace.hpp" - -#include -#include - -#include -#include - -using namespace MWGui; - -CursorReplace::CursorReplace() -{ - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45); - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45); -} diff --git a/apps/openmw/mwgui/cursorreplace.hpp b/apps/openmw/mwgui/cursorreplace.hpp deleted file mode 100644 index 06fe28e39a..0000000000 --- a/apps/openmw/mwgui/cursorreplace.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef GAME_CURSORREPLACE_H -#define GAME_CURSORREPLACE_H - -#include - -namespace MWGui -{ - /// \brief MyGUI does not support rotating cursors, so we have to do it manually - class CursorReplace - { - public: - CursorReplace(); - }; -} - -#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e17190b023..1138f62faa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -53,6 +53,7 @@ #include "trainingwindow.hpp" #include "imagebutton.hpp" #include "exposedwindow.hpp" +#include "cursor.hpp" using namespace MWGui; @@ -130,6 +131,9 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + MyGUI::ResourceManager::getInstance().load("core.xml"); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Get size info from the Gui object @@ -178,6 +182,8 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + mCursor = new Cursor(); + // The HUD is always on mHud->setVisible(true); @@ -236,6 +242,7 @@ WindowManager::~WindowManager() delete mTrainingWindow; delete mCountDialog; delete mQuickKeysMenu; + delete mCursor; cleanupGarbage(); @@ -262,6 +269,8 @@ void WindowManager::update() mHud->setFPS(mFPS); mHud->setTriangleCount(mTriangleCount); mHud->setBatchCount(mBatchCount); + + mCursor->update(); } void WindowManager::updateVisible() @@ -293,7 +302,7 @@ void WindowManager::updateVisible() mHud->setVisible(true); // Mouse is visible whenever we're not in game mode - MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); + mCursor->setVisible(isGuiMode()); bool gameMode = !isGuiMode(); @@ -421,7 +430,7 @@ void WindowManager::updateVisible() break; case GM_LoadingWallpaper: mHud->setVisible(false); - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); break; case GM_Loading: // Show the pinned windows @@ -430,10 +439,10 @@ void WindowManager::updateVisible() mInventoryWindow->setVisible(mInventoryWindow->pinned()); mSpellWindow->setVisible(mSpellWindow->pinned()); - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); break; case GM_Video: - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); mHud->setVisible(false); break; default: @@ -755,7 +764,7 @@ void WindowManager::setSpellVisibility(bool visible) void WindowManager::setMouseVisible(bool visible) { - MyGUI::PointerManager::getInstance().setVisible(visible); + mCursor->setVisible(visible); } void WindowManager::setDragDrop(bool dragDrop) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f574211372..e2d64a855d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -72,6 +72,7 @@ namespace MWGui class SpellCreationDialog; class EnchantingDialog; class TrainingWindow; + class Cursor; class WindowManager : public MWBase::WindowManager { @@ -260,6 +261,7 @@ namespace MWGui EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; Translation::Storage& mTranslationDataStorage; + Cursor* mCursor; CharacterCreation* mCharGen; diff --git a/files/mygui/openmw_pointer.xml b/files/mygui/openmw_pointer.xml index 42ee5d4351..cf21037f8e 100644 --- a/files/mygui/openmw_pointer.xml +++ b/files/mygui/openmw_pointer.xml @@ -5,26 +5,31 @@ + + - + + - + + - + + diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 5a695515d4..e47ff6386d 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -17,27 +17,6 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 925891e1b3..e5a164b818 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -53,7 +53,7 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Create GUI mGui = new Gui(); - mGui->initialise("core.xml"); + mGui->initialise(""); } void MyGUIManager::shutdown() From 166d529c5071bd88e59374cfa7ba9078e47eee86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 13:26:31 -0800 Subject: [PATCH 0544/1483] Ensure the material is properly built after creating it --- components/nifogre/ogre_nif_loader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 4d4a0d9c51..c856c4ab33 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -733,6 +733,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(((alphaFlags>>13)&1) ? "off" : "on"))); + sh::Factory::getInstance()._ensureMaterial(matname, "Default"); return matname; } From 238a8feb1819d1b1b430a0fd5211b13b71998e79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 13:27:25 -0800 Subject: [PATCH 0545/1483] Fix transparency checks --- apps/openmw/mwrender/activatoranimation.cpp | 9 +++---- apps/openmw/mwrender/creatureanimation.cpp | 9 +++---- apps/openmw/mwrender/npcanimation.cpp | 29 ++++++++++++++++----- apps/openmw/mwrender/objects.cpp | 11 ++++---- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index a3332d4b5c..0dc16ecb6f 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -31,19 +31,18 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) Ogre::Entity *ent = mEntityList.mEntities[i]; bool transparent = false; - for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) { Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements() && !transparent) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements() && !transparent) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 3adb0c4489..73bb80547d 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -32,19 +32,18 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) ent->setVisibilityFlags(RV_Actors); bool transparent = false; - for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) { Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements() && !transparent) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements() && !transparent) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ce15841fc6..1f1cd0530b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -107,19 +107,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setVisibilityFlags(mVisibilityFlags); bool transparent = false; - for(unsigned int j=0;j < base->getNumSubEntities();++j) + for(unsigned int j=0;!transparent && j < base->getNumSubEntities();++j) { Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } @@ -322,8 +321,26 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) { - parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + parts[i]->setVisibilityFlags(mVisibilityFlags); + + bool transparent = false; + for(unsigned int j=0;!transparent && j < parts[i]->getNumSubEntities();++j) + { + Ogre::MaterialPtr mat = parts[i]->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while(!transparent && techIt.hasMoreElements()) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while(!transparent && passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); + transparent = pass->isTransparent(); + } + } + } + parts[i]->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } if(entities.mSkelBase) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9aa65ac995..fb2b0e50a6 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -134,22 +134,21 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool mBounds[ptr.getCell()].merge(bounds); bool transparent = false; - for(size_t i = 0;i < entities.mEntities.size();i++) + for(size_t i = 0;!transparent && i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; - for (unsigned int i=0; igetNumSubEntities(); ++i) + for(unsigned int i=0;!transparent && i < ent->getNumSubEntities(); ++i) { Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } From 9810eafe230104ba4356bc5f53d6ee74bdaa3079 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 22:27:53 +0100 Subject: [PATCH 0546/1483] Removing now unused oengine/imagerotate --- CMakeLists.txt | 1 - libs/openengine/ogre/imagerotate.cpp | 88 ---------------------------- libs/openengine/ogre/imagerotate.hpp | 27 --------- 3 files changed, 116 deletions(-) delete mode 100644 libs/openengine/ogre/imagerotate.cpp delete mode 100644 libs/openengine/ogre/imagerotate.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b976df57a..e583f23d44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,6 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/fader.cpp - ${LIBDIR}/openengine/ogre/imagerotate.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp deleted file mode 100644 index 3dd5840785..0000000000 --- a/libs/openengine/ogre/imagerotate.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "imagerotate.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Ogre; -using namespace OEngine::Render; - -void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) -{ - Root* root = Ogre::Root::getSingletonPtr(); - - std::string destImageRot = std::string(destImage) + std::string("_rot"); - - SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); - Camera* camera = sceneMgr->createCamera("ImageRotateCamera"); - - MaterialPtr material = MaterialManager::getSingleton().create("ImageRotateMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - material->getTechnique(0)->getPass(0)->setLightingEnabled(false); - material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(sourceImage); - Degree deg(angle); - tus->setTextureRotate(Radian(deg.valueRadians())); - tus->setTextureAddressingMode(TextureUnitState::TAM_BORDER); - tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); - - Rectangle2D* rect = new Rectangle2D(true); - rect->setCorners(-1.0, 1.0, 1.0, -1.0); - rect->setMaterial("ImageRotateMaterial"); - // Render the background before everything else - rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); - - // Use infinite AAB to always stay visible - AxisAlignedBox aabInf; - aabInf.setInfinite(); - rect->setBoundingBox(aabInf); - - // Attach background to the scene - SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(rect); - - // retrieve image width and height - TexturePtr sourceTexture = TextureManager::getSingleton().getByName(sourceImage); - unsigned int width = sourceTexture->getWidth(); - unsigned int height = sourceTexture->getHeight(); - - TexturePtr destTextureRot = TextureManager::getSingleton().createManual( - destImageRot, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_FLOAT16_RGBA, - TU_RENDERTARGET); - - RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget(); - rtt->setAutoUpdated(false); - Viewport* vp = rtt->addViewport(camera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0,0,0,0)); - - rtt->update(); - - //copy the rotated image to a static texture - TexturePtr destTexture = TextureManager::getSingleton().createManual( - destImage, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_FLOAT16_RGBA, - Ogre::TU_STATIC); - - destTexture->getBuffer()->blit(destTextureRot->getBuffer()); - - // remove all the junk we've created - TextureManager::getSingleton().remove(destImageRot); - MaterialManager::getSingleton().remove("ImageRotateMaterial"); - root->destroySceneManager(sceneMgr); - delete rect; -} diff --git a/libs/openengine/ogre/imagerotate.hpp b/libs/openengine/ogre/imagerotate.hpp deleted file mode 100644 index a3f6d662f3..0000000000 --- a/libs/openengine/ogre/imagerotate.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef OENGINE_OGRE_IMAGEROTATE_HPP -#define OENGINE_OGRE_IMAGEROTATE_HPP - -#include - -namespace OEngine -{ -namespace Render -{ - - /// Rotate an image by certain degrees and save as file, uses the GPU - /// Make sure Ogre Root is initialised before calling - class ImageRotate - { - public: - /** - * @param source image (file name - has to exist in an resource group) - * @param name of the destination texture to save to (in memory) - * @param angle in degrees to turn - */ - static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle); - }; - -} -} - -#endif From ef1678e47eaf1974fd8322b8c1b70c6653965b15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 22:32:02 +0100 Subject: [PATCH 0547/1483] Oops, rotation center should be dynamic --- apps/openmw/mwgui/cursor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 852eea29a4..15f61d5b66 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -110,7 +110,7 @@ namespace MWGui mWidget->setImageTexture(texture); MyGUI::ISubWidget* main = mWidget->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + rotatingSubskin->setCenter(MyGUI::IntPoint(mSize.width/2,mSize.height/2)); rotatingSubskin->setAngle(Ogre::Degree(rotation).valueRadians()); } From ccb7ed93b3d231c112b7ab7541178e19cb2adcf3 Mon Sep 17 00:00:00 2001 From: lazydev Date: Sat, 2 Mar 2013 03:54:25 +0400 Subject: [PATCH 0548/1483] fix for https://bugs.openmw.org/issues/593 --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +++- apps/openmw/mwdialogue/filter.cpp | 34 ++++++++++++++----- apps/openmw/mwdialogue/filter.hpp | 3 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f548c46f75..43d201fbf3 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -251,8 +251,12 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - if (const ESM::DialInfo *info = filter.search (dialogue, true)) + std::vector infos; + filter.search (infos, dialogue, true, true); + if (!infos.empty()) { + const ESM::DialInfo* info = infos[rand() % infos.size()]; + parseText (info->mResponse); if (dialogue.mType==ESM::Dialogue::Persuasion) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 6f9d8b42fc..4391716fd6 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -559,8 +559,22 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) {} -const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const +const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const { + std::vector suitableInfos; + search(suitableInfos, dialogue, fallbackToInfoRefusal, false); + + if (suitableInfos.empty()) + return NULL; + else + return suitableInfos[0]; +} + +void MWDialogue::Filter::search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, + const bool fallbackToInfoRefusal, bool searchAll) const +{ + suitableInfos.clear(); + bool infoRefusal = false; // Iterate over topic responses to find a matching one @@ -569,14 +583,17 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { - if (testDisposition (*iter)) - return &*iter; + if (testDisposition (*iter)) { + suitableInfos.push_back(&*iter); + if (!searchAll) + return; + } else infoRefusal = true; } } - if (infoRefusal && fallbackToInfoRefusal) + if (suitableInfos.empty() && infoRefusal && fallbackToInfoRefusal) { // No response is valid because of low NPC disposition, // search a response in the topic "Info Refusal" @@ -588,11 +605,12 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) - if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) - return &*iter; + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { + suitableInfos.push_back(&*iter); + if (!searchAll) + return; + } } - - return 0; } bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 707c0154b6..e1e22a51ca 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -51,7 +51,8 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; + void search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal, bool searchAll) const; + const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. From e3fd4b842954e31e15e81cd71eb4ad2b5acca69f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 17:57:34 -0800 Subject: [PATCH 0549/1483] Fix restoring the original texture name when the DDS check fails --- components/nifogre/ogre_nif_loader.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 0b53177e13..d33243dd47 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -621,7 +621,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) // verify, and revert if false (this call succeeds quickly, but fails slowly) if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = path + Misc::StringUtils::lowerCase(texName); + { + texName = st->filename; + Misc::StringUtils::toLower(texName); + if(texName.compare(0, sizeof(path)-1, path) != 0) + texName = path + texName; + } } } else warn("Found internal texture, ignoring."); From 0f4f91605a402f636e45ac81cd45708eab6fa121 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Mar 2013 11:19:48 +0100 Subject: [PATCH 0550/1483] some cleanup --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 7 ++++--- apps/openmw/mwdialogue/filter.cpp | 21 ++++++++++--------- apps/openmw/mwdialogue/filter.hpp | 6 +++++- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 43d201fbf3..35f0c94937 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -2,6 +2,7 @@ #include "dialoguemanagerimp.hpp" #include +#include #include #include @@ -251,11 +252,11 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - std::vector infos; - filter.search (infos, dialogue, true, true); + std::vector infos = filter.list (dialogue, true, true); + if (!infos.empty()) { - const ESM::DialInfo* info = infos[rand() % infos.size()]; + const ESM::DialInfo* info = infos[std::rand() % infos.size()]; parseText (info->mResponse); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 4391716fd6..10740794ea 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -561,8 +561,7 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const { - std::vector suitableInfos; - search(suitableInfos, dialogue, fallbackToInfoRefusal, false); + std::vector suitableInfos = list (dialogue, fallbackToInfoRefusal, false); if (suitableInfos.empty()) return NULL; @@ -570,10 +569,10 @@ const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, return suitableInfos[0]; } -void MWDialogue::Filter::search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, - const bool fallbackToInfoRefusal, bool searchAll) const +std::vector MWDialogue::Filter::list (const ESM::Dialogue& dialogue, + bool fallbackToInfoRefusal, bool searchAll) const { - suitableInfos.clear(); + std::vector infos; bool infoRefusal = false; @@ -584,16 +583,16 @@ void MWDialogue::Filter::search (std::vector& suitableInfo if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { if (testDisposition (*iter)) { - suitableInfos.push_back(&*iter); + infos.push_back(&*iter); if (!searchAll) - return; + break; } else infoRefusal = true; } } - if (suitableInfos.empty() && infoRefusal && fallbackToInfoRefusal) + if (infos.empty() && infoRefusal && fallbackToInfoRefusal) { // No response is valid because of low NPC disposition, // search a response in the topic "Info Refusal" @@ -606,11 +605,13 @@ void MWDialogue::Filter::search (std::vector& suitableInfo for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { - suitableInfos.push_back(&*iter); + infos.push_back(&*iter); if (!searchAll) - return; + break; } } + + return infos; } bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index e1e22a51ca..069bf6353d 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWDIALOGUE_FILTER_H #define GAME_MWDIALOGUE_FILTER_H +#include + #include "../mwworld/ptr.hpp" namespace ESM @@ -51,7 +53,9 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - void search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal, bool searchAll) const; + std::vector list (const ESM::Dialogue& dialogue, + bool fallbackToInfoRefusal, bool searchAll) const; + const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. From e1957e4ee900b31eabb2f3fb9e90fb89d38d1958 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 Mar 2013 13:34:26 +0100 Subject: [PATCH 0551/1483] Potion effects should be hidden until discovered --- apps/openmw/mwclass/potion.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index c3a6df2112..0ac78a2e40 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -20,6 +20,8 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwmechanics/npcstats.hpp" + namespace MWClass { void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -138,6 +140,23 @@ namespace MWClass text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects); + + // hide effects the player doesnt know about + 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(); + int i=0; + for (MWGui::Widgets::SpellEffectList::iterator it = info.effects.begin(); it != info.effects.end(); ++it) + { + /// \todo this code is duplicated from mwclass/ingredient, put it in a helper function + it->mKnown = ( (i == 0 && alchemySkill >= 15) + || (i == 1 && alchemySkill >= 30) + || (i == 2 && alchemySkill >= 45) + || (i == 3 && alchemySkill >= 60)); + + ++i; + } + info.isPotion = true; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { From f85be6a7441d9dfb8b49d40b52a012088c636600 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 2 Mar 2013 07:57:41 -0600 Subject: [PATCH 0552/1483] 80% complete save-on-close feature --- apps/opencs/view/doc/operations.cpp | 2 +- apps/opencs/view/doc/view.cpp | 10 ++- apps/opencs/view/doc/view.hpp | 5 +- apps/opencs/view/doc/viewmanager.cpp | 121 ++++++++++++++++++++++++--- apps/opencs/view/doc/viewmanager.hpp | 7 +- 5 files changed, 129 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index 71cacbe17e..58cef13430 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -54,7 +54,7 @@ void CSVDoc::Operations::quitOperation (int type) mLayout->removeItem ((*iter)->getLayout()); - delete *iter; + (*iter)->deleteLater(); mOperations.erase (iter); if (oldCount > 1) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 6aafef4ed0..49dd2fc8a9 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -18,10 +18,14 @@ #include "operations.hpp" #include "subview.hpp" +#include void CSVDoc::View::closeEvent (QCloseEvent *event) { if (!mViewManager.closeRequest (this)) + { + qDebug() << "ignoring event"; event->ignore(); + } } void CSVDoc::View::setupFileMenu() @@ -117,9 +121,11 @@ void CSVDoc::View::updateActions() mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); } -CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent) - : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), QMainWindow (viewParent) +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) //, QMainWindow *viewParent) + : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), + mViewTotal (totalViews) //, QMainWindow (viewParent) { + setAttribute (Qt::WA_DeleteOnClose, true); setDockOptions (QMainWindow::AllowNestedDocks); resize (300, 300); /// \todo get default size from settings and set reasonable minimal size diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 28ab24b744..f50a0550ee 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -67,7 +67,7 @@ namespace CSVDoc public: - View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent); + View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); //, QMainWindow *viewParent); ///< The ownership of \a document is not transferred to *this. virtual ~View(); @@ -94,6 +94,8 @@ namespace CSVDoc void addSubView (const CSMWorld::UniversalId& id); + void abortOperation (int type); + private slots: void newView(); @@ -106,7 +108,6 @@ namespace CSVDoc void addGmstsSubView(); - void abortOperation (int type); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a8faefb970..59e53dfe07 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -12,6 +12,10 @@ #include "view.hpp" +#include +#include + + void CSVDoc::ViewManager::updateIndices() { std::map > documents; @@ -31,7 +35,7 @@ void CSVDoc::ViewManager::updateIndices() } CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) -: mDocumentManager (documentManager) + : mDocumentManager (documentManager), mCloseMeOnSaveStateChange(0) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; @@ -59,9 +63,9 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); } - QMainWindow *mainWindow = new QMainWindow; + // QMainWindow *mainWindow = new QMainWindow; - View *view = new View (*this, document, countViews (document)+1, mainWindow); + View *view = new View (*this, document, countViews (document)+1); //, mainWindow); mViews.push_back (view); @@ -90,6 +94,8 @@ bool CSVDoc::ViewManager::closeRequest (View *view) { std::vector::iterator iter = std::find (mViews.begin(), mViews.end(), view); + bool continueWithClose = true; + if (iter!=mViews.end()) { bool last = countViews (view->getDocument())<=1; @@ -97,16 +103,98 @@ bool CSVDoc::ViewManager::closeRequest (View *view) /// \todo check if save is in progress -> warn user about possible data loss /// \todo check if document has not been saved -> return false and start close dialogue - mViews.erase (iter); - view->deleteLater(); + CSMDoc::Document *document = view->getDocument(); - if (last) - mDocumentManager.removeDocument (view->getDocument()); - else - updateIndices(); + //notify user of unsaved changes and process response + if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (view); + + //notify user of saving in progress + if ( document->getState() & CSMDoc::State_Saving ) + continueWithClose = showSaveInProgressMessageBox (view); + + qDebug() << "Continue with close? " << continueWithClose; + + if (continueWithClose) + { + mViews.erase (iter); + + if (last) + mDocumentManager.removeDocument (document); + else + updateIndices(); + } } - return true; + return continueWithClose; +} + +bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) +{ + QMessageBox messageBox; + + messageBox.setText ("The document has been modified."); + messageBox.setInformativeText ("Do you want to save your changes?"); + messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + messageBox.setDefaultButton (QMessageBox::Save); + + bool retVal = true; + + switch (messageBox.exec()) + { + case QMessageBox::Save: + view->getDocument()->save(); + mCloseMeOnSaveStateChange = view; + retVal = false; + break; + + case QMessageBox::Discard: + break; + + case QMessageBox::Cancel: + retVal = false; + break; + + default: + break; + + } + + return retVal; +} + +bool CSVDoc::ViewManager::showSaveInProgressMessageBox (View* view) +{ + QMessageBox messageBox; + + messageBox.setText ("The document is currently being saved."); + messageBox.setInformativeText("Do you want to abort the save?"); + messageBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + + bool retVal = false; + + switch (messageBox.exec()) + { + case QMessageBox::Yes: + view->abortOperation(CSMDoc::State_Saving); + // mCloseMeOnSaveStateChange = view; + retVal = false; + break; + + case QMessageBox::No: + //mCloseMeOnSaveStateChange = view; + retVal = false; + break; + + case QMessageBox::Cancel: + retVal = false; + break; + + default: + break; + } + + return retVal; } void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document) @@ -114,6 +202,19 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) (*iter)->updateDocumentState(); + + if (mPreviousDocumentState & CSMDoc::State_Saving) + qDebug() << "Last state was saving"; + else + qDebug() << "Last state was something else"; +/* + if (mCloseMeOnSaveStateChange && (mPreviousDocumentState & CSMDoc::State_Saving)) + { + mCloseMeOnSaveStateChange->close(); + mCloseMeOnSaveStateChange = 0; + } +*/ + mPreviousDocumentState = state; } void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, CSMDoc::Document *document) diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 72e7a3e1a1..2517f8ccbe 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -27,12 +27,17 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; + View *mCloseMeOnSaveStateChange; + int mPreviousDocumentState; // not implemented ViewManager (const ViewManager&); ViewManager& operator= (const ViewManager&); void updateIndices(); + bool showModifiedDocumentMessageBox (View* view); + bool showSaveInProgressMessageBox (View* view); + public: @@ -63,4 +68,4 @@ namespace CSVDoc } -#endif \ No newline at end of file +#endif From a2e36594c97eface26fabeee13c27e1f84ff8351 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 2 Mar 2013 09:22:44 -0600 Subject: [PATCH 0553/1483] Completed "abort save on close" feature --- apps/opencs/view/doc/view.cpp | 4 ++-- apps/opencs/view/doc/view.hpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 23 ++++++++++++----------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 49dd2fc8a9..b4d137be2e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -121,9 +121,9 @@ void CSVDoc::View::updateActions() mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); } -CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) //, QMainWindow *viewParent) +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), - mViewTotal (totalViews) //, QMainWindow (viewParent) + mViewTotal (totalViews) { setAttribute (Qt::WA_DeleteOnClose, true); setDockOptions (QMainWindow::AllowNestedDocks); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index f50a0550ee..d436aebe76 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -67,7 +67,7 @@ namespace CSVDoc public: - View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); //, QMainWindow *viewParent); + View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); ///< The ownership of \a document is not transferred to *this. virtual ~View(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 59e53dfe07..02407dfcde 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -171,22 +171,22 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (View* view) messageBox.setInformativeText("Do you want to abort the save?"); messageBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); - bool retVal = false; + bool retVal = true; switch (messageBox.exec()) { - case QMessageBox::Yes: + case QMessageBox::Yes: //immediate shutdown + mCloseMeOnSaveStateChange = 0; view->abortOperation(CSMDoc::State_Saving); - // mCloseMeOnSaveStateChange = view; + break; + + case QMessageBox::No: //shutdown after save completes + mCloseMeOnSaveStateChange = view; retVal = false; break; - case QMessageBox::No: - //mCloseMeOnSaveStateChange = view; - retVal = false; - break; - - case QMessageBox::Cancel: + case QMessageBox::Cancel: //abort shutdown, allow save to complete + mCloseMeOnSaveStateChange = 0; retVal = false; break; @@ -207,13 +207,14 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc qDebug() << "Last state was saving"; else qDebug() << "Last state was something else"; -/* + + //mechanism to shutdown main window after saving operation completes if (mCloseMeOnSaveStateChange && (mPreviousDocumentState & CSMDoc::State_Saving)) { mCloseMeOnSaveStateChange->close(); mCloseMeOnSaveStateChange = 0; } -*/ + mPreviousDocumentState = state; } From 9acd4061ccc2ff497cca8e18baa4052beb073da3 Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 2 Mar 2013 17:04:17 +0100 Subject: [PATCH 0554/1483] Fix dangling static references in mShared --- apps/openmw/mwworld/store.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 5fad63ff52..52120ed0ec 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,6 +187,15 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); + // delete from static part of shared + typename std::vector::iterator sharedit = mShared.begin(); + for (; sharedit != (mShared.begin()+mStatic.size()); ++sharedit) { + if((*sharedit)->mId == item.mId) { + mShared.erase(sharedit); + break; + } + } + typename std::map::iterator it = mStatic.find(item.mId); if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { From 6de6d9ff6eabc79236b206a09c710b85ec4135f9 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 13:03:05 -0800 Subject: [PATCH 0555/1483] Factored a NIFStream class out of the NIFFile class. Split NIFFile into two parts, NIFFile which is cached and is a container for a parsed NIF, and NIFStream which is a class specialized for parsing NIFs. This required a semi-sweeping change to make all record classes accept a NIFStream instead of a NIFFile as an agurment to their read functions. --- components/nif/controlled.hpp | 14 +-- components/nif/controller.hpp | 18 ++-- components/nif/data.hpp | 30 +++--- components/nif/effect.hpp | 6 +- components/nif/extra.hpp | 8 +- components/nif/nif_file.cpp | 15 ++- components/nif/nif_file.hpp | 154 ++---------------------------- components/nif/nif_stream.hpp | 175 ++++++++++++++++++++++++++++++++++ components/nif/node.hpp | 14 +-- components/nif/property.hpp | 16 ++-- components/nif/record.hpp | 3 +- components/nif/record_ptr.hpp | 4 +- 12 files changed, 249 insertions(+), 208 deletions(-) create mode 100644 components/nif/nif_stream.hpp diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index b9d84b58ab..dac541b2d0 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -36,7 +36,7 @@ class Controlled : public Extra public: ControllerPtr controller; - void read(NIFFile *nif) + void read(NIFStream *nif) { Extra::read(nif); controller.read(nif); @@ -55,7 +55,7 @@ class Named : public Controlled public: std::string name; - void read(NIFFile *nif) + void read(NIFStream *nif) { name = nif->getString(); Controlled::read(nif); @@ -66,7 +66,7 @@ typedef Named NiSequenceStreamHelper; class NiParticleGrowFade : public Controlled { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); @@ -80,7 +80,7 @@ class NiParticleColorModifier : public Controlled public: NiColorDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); data.read(nif); @@ -96,7 +96,7 @@ public: class NiGravity : public Controlled { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); @@ -109,7 +109,7 @@ public: class NiPlanarCollider : public Controlled { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); @@ -121,7 +121,7 @@ public: class NiParticleRotation : public Controlled { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index cbc19cd8f5..4f7ef3c0f7 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -40,7 +40,7 @@ public: float timeStart, timeStop; ControlledPtr target; - void read(NIFFile *nif) + void read(NIFStream *nif) { next.read(nif); @@ -65,7 +65,7 @@ public: class NiBSPArrayController : public Controller { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); @@ -82,7 +82,7 @@ class NiMaterialColorController : public Controller public: NiPosDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); @@ -101,7 +101,7 @@ public: NiPosDataPtr posData; NiFloatDataPtr floatData; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); @@ -129,7 +129,7 @@ class NiUVController : public Controller public: NiUVDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); @@ -149,7 +149,7 @@ class NiKeyframeController : public Controller public: NiKeyframeDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); @@ -167,7 +167,7 @@ class NiAlphaController : public Controller public: NiFloatDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); @@ -185,7 +185,7 @@ class NiGeomMorpherController : public Controller public: NiMorphDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); @@ -204,7 +204,7 @@ class NiVisController : public Controller public: NiVisDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 46b58da8f9..5f18800f0b 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -65,7 +65,7 @@ public: */ int alpha; - void read(NIFFile *nif) + void read(NIFStream *nif) { Named::read(nif); @@ -102,7 +102,7 @@ public: Ogre::Vector3 center; float radius; - void read(NIFFile *nif) + void read(NIFStream *nif) { int verts = nif->getUShort(); @@ -138,7 +138,7 @@ public: // Triangles, three vertex indices per triangle std::vector triangles; - void read(NIFFile *nif) + void read(NIFStream *nif) { ShapeData::read(nif); @@ -167,7 +167,7 @@ class NiAutoNormalParticlesData : public ShapeData public: int activeCount; - void read(NIFFile *nif) + void read(NIFStream *nif) { ShapeData::read(nif); @@ -189,7 +189,7 @@ public: class NiRotatingParticlesData : public NiAutoNormalParticlesData { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { NiAutoNormalParticlesData::read(nif); @@ -208,7 +208,7 @@ class NiPosData : public Record public: Vector3KeyList mKeyList; - void read(NIFFile *nif) + void read(NIFStream *nif) { mKeyList.read(nif); } @@ -219,7 +219,7 @@ class NiUVData : public Record public: FloatKeyList mKeyList[4]; - void read(NIFFile *nif) + void read(NIFStream *nif) { for(int i = 0;i < 4;i++) mKeyList[i].read(nif); @@ -231,7 +231,7 @@ class NiFloatData : public Record public: FloatKeyList mKeyList; - void read(NIFFile *nif) + void read(NIFStream *nif) { mKeyList.read(nif); } @@ -243,7 +243,7 @@ public: unsigned int rmask, gmask, bmask, amask; int bpp, mips; - void read(NIFFile *nif) + void read(NIFStream *nif) { nif->getInt(); // always 0 or 1 @@ -281,7 +281,7 @@ class NiColorData : public Record public: Vector4KeyList mKeyList; - void read(NIFFile *nif) + void read(NIFStream *nif) { mKeyList.read(nif); } @@ -295,7 +295,7 @@ public: char isSet; }; - void read(NIFFile *nif) + void read(NIFStream *nif) { int count = nif->getInt(); @@ -311,7 +311,7 @@ public: NodePtr root; NodeList bones; - void read(NIFFile *nif) + void read(NIFStream *nif) { data.read(nif); root.read(nif); @@ -347,7 +347,7 @@ public: BoneTrafo trafo; std::vector bones; - void read(NIFFile *nif) + void read(NIFStream *nif) { trafo.rotation = nif->getMatrix3(); trafo.trans = nif->getVector3(); @@ -385,7 +385,7 @@ struct NiMorphData : public Record }; std::vector mMorphs; - void read(NIFFile *nif) + void read(NIFStream *nif) { int morphCount = nif->getInt(); int vertCount = nif->getInt(); @@ -410,7 +410,7 @@ struct NiKeyframeData : public Record Vector3KeyList mTranslations; FloatKeyList mScales; - void read(NIFFile *nif) + void read(NIFStream *nif) { mRotations.read(nif); mTranslations.read(nif); diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 850415dadc..b07a39303c 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -42,7 +42,7 @@ struct NiLight : Effect Ogre::Vector3 diffuse; Ogre::Vector3 specular; - void read(NIFFile *nif) + void read(NIFStream *nif) { dimmer = nif->getFloat(); ambient = nif->getVector3(); @@ -52,7 +52,7 @@ struct NiLight : Effect }; SLight light; - void read(NIFFile *nif) + void read(NIFStream *nif) { Effect::read(nif); @@ -66,7 +66,7 @@ struct NiTextureEffect : Effect { NiSourceTexturePtr texture; - void read(NIFFile *nif) + void read(NIFStream *nif) { Effect::read(nif); diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index 35781dbf59..b5335f9871 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -40,14 +40,14 @@ class Extra : public Record public: ExtraPtr extra; - void read(NIFFile *nif) { extra.read(nif); } + void read(NIFStream *nif) { extra.read(nif); } void post(NIFFile *nif) { extra.post(nif); } }; class NiVertWeightsExtraData : public Extra { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Extra::read(nif); @@ -70,7 +70,7 @@ public: }; std::vector list; - void read(NIFFile *nif) + void read(NIFStream *nif) { Extra::read(nif); @@ -95,7 +95,7 @@ public: */ std::string string; - void read(NIFFile *nif) + void read(NIFStream *nif) { Extra::read(nif); diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 6e806e7ecc..f3faf563cc 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -174,10 +174,7 @@ NIFFile::ptr NIFFile::create (const std::string &name) { return LoadedCache::cre NIFFile::NIFFile(const std::string &name, psudo_private_modifier) : filename(name) { - inp = Ogre::ResourceGroupManager::getSingleton().openResource(name); parse(); - // Make sure to close the file after it was loaded into memory - inp.setNull(); } NIFFile::~NIFFile() @@ -195,18 +192,20 @@ NIFFile::~NIFFile() void NIFFile::parse() { + NIFStream nif (this, Ogre::ResourceGroupManager::getSingleton().openResource(filename)); + // Check the header string - std::string head = getString(40); + std::string head = nif.getString(40); if(head.compare(0, 22, "NetImmerse File Format") != 0) fail("Invalid NIF header"); // Get BCD version - ver = getInt(); + ver = nif.getInt(); if(ver != VER_MW) fail("Unsupported NIF version"); // Number of records - size_t recNum = getInt(); + size_t recNum = nif.getInt(); records.resize(recNum); /* The format for 10.0.1.0 seems to be a bit different. After the @@ -222,7 +221,7 @@ void NIFFile::parse() { Record *r = NULL; - std::string rec = getString(); + std::string rec = nif.getString(); /* These are all the record types we know how to read. @@ -312,7 +311,7 @@ void NIFFile::parse() r->recName = rec; r->recIndex = i; records[i] = r; - r->read(this); + r->read(&nif); // Discard tranformations for the root node, otherwise some meshes // occasionally get wrong orientation. Only for NiNode-s for now, but diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index 5e9694f4b4..a406de4a0c 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -46,6 +46,7 @@ #include "record.hpp" #include "nif_types.hpp" +#include "nif_stream.hpp" namespace Nif { @@ -59,9 +60,6 @@ class NIFFile /// Nif file version int ver; - /// Input stream - Ogre::DataStreamPtr inp; - /// File name, used for error messages std::string filename; @@ -71,33 +69,6 @@ class NIFFile /// Parse the file void parse(); - uint8_t read_byte() - { - uint8_t byte; - if(inp->read(&byte, 1) != 1) return 0; - return byte; - } - uint16_t read_le16() - { - uint8_t buffer[2]; - if(inp->read(buffer, 2) != 2) return 0; - return buffer[0] | (buffer[1]<<8); - } - uint32_t read_le32() - { - uint8_t buffer[4]; - if(inp->read(buffer, 4) != 4) return 0; - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); - } - float read_le32f() - { - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; - } - class LoadedCache; friend class LoadedCache; @@ -117,8 +88,8 @@ public: void warn(const std::string &msg) { - std::cerr<< "NIFFile Warning: "< ptr; @@ -147,111 +118,6 @@ public: /// Number of records size_t numRecords() { return records.size(); } - - /************************************************* - Parser functions - ****************************************************/ - - void skip(size_t size) { inp->skip(size); } - - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - unsigned int getUInt() { 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]; - for(size_t i = 0;i < 3;i++) - a[i] = getFloat(); - return Ogre::Vector3(a); - } - Ogre::Vector4 getVector4() - { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Vector4(a); - } - Ogre::Matrix3 getMatrix3() - { - Ogre::Real a[3][3]; - for(size_t i = 0;i < 3;i++) - { - for(size_t j = 0;j < 3;j++) - a[i][j] = Ogre::Real(getFloat()); - } - return Ogre::Matrix3(a); - } - Ogre::Quaternion getQuaternion() - { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Quaternion(a); - } - Transformation getTrafo() - { - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; - } - - std::string getString(size_t length) - { - std::vector str (length+1, 0); - - if(inp->read(&str[0], length) != length) - throw std::runtime_error ("string length in NIF file does not match"); - - return &str[0]; - } - std::string getString() - { - size_t size = read_le32(); - return getString(size); - } - - void getShorts(std::vector &vec, size_t size) - { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); - } - void getFloats(std::vector &vec, size_t size) - { - vec.resize(size); - 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(); - } }; @@ -270,7 +136,7 @@ typedef KeyT Vector3Key; typedef KeyT Vector4Key; typedef KeyT QuaternionKey; -template +template struct KeyListT { typedef std::vector< KeyT > VecType; @@ -281,7 +147,7 @@ struct KeyListT { int mInterpolationType; VecType mKeys; - void read(NIFFile *nif, bool force=false) + void read(NIFStream *nif, bool force=false) { size_t count = nif->getInt(); if(count == 0 && !force) @@ -322,13 +188,13 @@ struct KeyListT { } } else - nif->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); } }; -typedef KeyListT FloatKeyList; -typedef KeyListT Vector3KeyList; -typedef KeyListT Vector4KeyList; -typedef KeyListT QuaternionKeyList; +typedef KeyListT FloatKeyList; +typedef KeyListT Vector3KeyList; +typedef KeyListT Vector4KeyList; +typedef KeyListT QuaternionKeyList; } // Namespace #endif diff --git a/components/nif/nif_stream.hpp b/components/nif/nif_stream.hpp new file mode 100644 index 0000000000..8fb98f3d65 --- /dev/null +++ b/components/nif/nif_stream.hpp @@ -0,0 +1,175 @@ +#ifndef _NIF_STREAM_HPP_ +#define _NIF_STREAM_HPP_ + +namespace Nif +{ + +class NIFFile; + +class NIFStream { + + /// Input stream + Ogre::DataStreamPtr inp; + + uint8_t read_byte() + { + uint8_t byte; + if(inp->read(&byte, 1) != 1) return 0; + return byte; + } + uint16_t read_le16() + { + uint8_t buffer[2]; + if(inp->read(buffer, 2) != 2) return 0; + return buffer[0] | (buffer[1]<<8); + } + uint32_t read_le32() + { + uint8_t buffer[4]; + if(inp->read(buffer, 4) != 4) return 0; + return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); + } + float read_le32f() + { + union { + uint32_t i; + float f; + } u = { read_le32() }; + return u.f; + } + +public: + + NIFFile * const file; + + NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + + /************************************************* + Parser functions + ****************************************************/ + + template + struct GetHandler + { + typedef T (NIFStream::*fn_t)(); + + static const fn_t sValue; // this is specialized per supported type in the .cpp file + + static T read (NIFStream* nif) + { + return (nif->*sValue) (); + } + }; + + template + void read (NIFStream* nif, T & Value) + { + Value = GetHandler ::read (nif); + } + + void skip(size_t size) { inp->skip(size); } + void read (void * data, size_t size) { inp->read (data, size); } + + char getChar() { return read_byte(); } + short getShort() { return read_le16(); } + unsigned short getUShort() { return read_le16(); } + int getInt() { return read_le32(); } + int getUInt() { 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]; + for(size_t i = 0;i < 3;i++) + a[i] = getFloat(); + return Ogre::Vector3(a); + } + Ogre::Vector4 getVector4() + { + float a[4]; + for(size_t i = 0;i < 4;i++) + a[i] = getFloat(); + return Ogre::Vector4(a); + } + Ogre::Matrix3 getMatrix3() + { + Ogre::Real a[3][3]; + for(size_t i = 0;i < 3;i++) + { + for(size_t j = 0;j < 3;j++) + a[i][j] = Ogre::Real(getFloat()); + } + return Ogre::Matrix3(a); + } + Ogre::Quaternion getQuaternion() + { + float a[4]; + for(size_t i = 0;i < 4;i++) + a[i] = getFloat(); + return Ogre::Quaternion(a); + } + Transformation getTrafo() + { + Transformation t; + t.pos = getVector3(); + t.rotation = getMatrix3(); + t.scale = getFloat(); + return t; + } + + std::string getString(size_t length) + { + std::vector str (length+1, 0); + + if(inp->read(&str[0], length) != length) + throw std::runtime_error ("string length in NIF file does not match"); + + return &str[0]; + } + std::string getString() + { + size_t size = read_le32(); + return getString(size); + } + + void getShorts(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getShort(); + } + void getFloats(std::vector &vec, size_t size) + { + vec.resize(size); + 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(); + } +}; + +} + +#endif diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 07e7868cce..e087037565 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -54,7 +54,7 @@ public: Ogre::Matrix3 boundRot; Ogre::Vector3 boundXYZ; // Box size - void read(NIFFile *nif) + void read(NIFStream *nif) { Named::read(nif); @@ -128,7 +128,7 @@ struct NiNode : Node 0x20, 0x40, 0x80 unknown */ - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); children.read(nif); @@ -162,7 +162,7 @@ struct NiTriShape : Node NiTriShapeDataPtr data; NiSkinInstancePtr skin; - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); data.read(nif); @@ -190,7 +190,7 @@ struct NiCamera : Node // Level of detail modifier float LOD; - void read(NIFFile *nif) + void read(NIFStream *nif) { left = nif->getFloat(); right = nif->getFloat(); @@ -209,7 +209,7 @@ struct NiCamera : Node }; Camera cam; - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); @@ -224,7 +224,7 @@ struct NiAutoNormalParticles : Node { NiAutoNormalParticlesDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); data.read(nif); @@ -242,7 +242,7 @@ struct NiRotatingParticles : Node { NiRotatingParticlesDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); data.read(nif); diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 046fb04652..cdf97986c3 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -35,7 +35,7 @@ public: // The meaning of these depends on the actual property type. int flags; - void read(NIFFile *nif) + void read(NIFStream *nif) { Named::read(nif); flags = nif->getUShort(); @@ -67,7 +67,7 @@ public: int clamp, set, filter; short unknown2; - void read(NIFFile *nif) + void read(NIFStream *nif) { inUse = !!nif->getInt(); if(!inUse) return; @@ -111,7 +111,7 @@ public: */ Texture textures[7]; - void read(NIFFile *nif) + void read(NIFStream *nif) { Property::read(nif); apply = nif->getInt(); @@ -157,7 +157,7 @@ struct StructPropT : Property { T data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Property::read(nif); data.read(nif); @@ -170,7 +170,7 @@ struct S_MaterialProperty Ogre::Vector3 ambient, diffuse, specular, emissive; float glossiness, alpha; - void read(NIFFile *nif) + void read(NIFStream *nif) { ambient = nif->getVector3(); diffuse = nif->getVector3(); @@ -194,7 +194,7 @@ struct S_VertexColorProperty */ int vertmode, lightmode; - void read(NIFFile *nif) + void read(NIFStream *nif) { vertmode = nif->getInt(); lightmode = nif->getInt(); @@ -251,7 +251,7 @@ struct S_AlphaProperty // Tested against when certain flags are set (see above.) unsigned char threshold; - void read(NIFFile *nif) + void read(NIFStream *nif) { threshold = nif->getChar(); } @@ -300,7 +300,7 @@ struct S_StencilProperty */ int drawMode; - void read(NIFFile *nif) + void read(NIFStream *nif) { enabled = nif->getChar(); compareFunc = nif->getInt(); diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 073f4657c0..9f0645dfdf 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -30,6 +30,7 @@ namespace Nif { class NIFFile; +class NIFStream; enum RecordType { @@ -97,7 +98,7 @@ struct Record Record() : recType(RC_MISSING), recIndex(~(size_t)0) {} /// Parses the record from file - virtual void read(NIFFile *nif) = 0; + virtual void read(NIFStream *nif) = 0; /// Does post-processing, after the entire tree is loaded virtual void post(NIFFile *nif) {} diff --git a/components/nif/record_ptr.hpp b/components/nif/record_ptr.hpp index ef5bb1deec..855099a04a 100644 --- a/components/nif/record_ptr.hpp +++ b/components/nif/record_ptr.hpp @@ -46,7 +46,7 @@ public: RecordPtrT() : index(-2) {} /// Read the index from the nif - void read(NIFFile *nif) + void read(NIFStream *nif) { // Can only read the index once assert(index == -2); @@ -99,7 +99,7 @@ class RecordListT std::vector list; public: - void read(NIFFile *nif) + void read(NIFStream *nif) { int len = nif->getInt(); list.resize(len); From 0ed2015319a0afa2c59a393e7e876572af419134 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 3 Jan 2013 23:59:32 -0800 Subject: [PATCH 0556/1483] refactored NIFFile parse to get better code/data seperation --- components/nif/nif_file.cpp | 182 ++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 80 deletions(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index f3faf563cc..dc8670cba2 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -185,6 +185,101 @@ NIFFile::~NIFFile() delete records[i]; } +template static Record* construct() { return new NodeType; } + +struct RecordFactoryEntry { + + typedef Record* (*create_t) (); + + char const * mName; + create_t mCreate; + RecordType mType; + +}; + +/* These are all the record types we know how to read. + + This can be heavily optimized later if needed. For example, a + hash table or a FSM-based parser could be used to look up + node names. +*/ + +static const RecordFactoryEntry recordFactories [] = { + + { "NiNode", &construct , RC_NiNode }, + { "AvoidNode", &construct , RC_NiNode }, + { "NiBSParticleNode", &construct , RC_NiNode }, + { "NiBSAnimationNode", &construct , RC_NiNode }, + { "NiBillboardNode", &construct , RC_NiNode }, + { "NiTriShape", &construct , RC_NiTriShape }, + { "NiRotatingParticles", &construct , RC_NiRotatingParticles }, + { "NiAutoNormalParticles", &construct , RC_NiAutoNormalParticles }, + { "NiCamera", &construct , RC_NiCamera }, + { "RootCollisionNode", &construct , RC_RootCollisionNode }, + { "NiTexturingProperty", &construct , RC_NiTexturingProperty }, + { "NiMaterialProperty", &construct , RC_NiMaterialProperty }, + { "NiZBufferProperty", &construct , RC_NiZBufferProperty }, + { "NiAlphaProperty", &construct , RC_NiAlphaProperty }, + { "NiVertexColorProperty", &construct , RC_NiVertexColorProperty }, + { "NiShadeProperty", &construct , RC_NiShadeProperty }, + { "NiDitherProperty", &construct , RC_NiDitherProperty }, + { "NiWireframeProperty", &construct , RC_NiWireframeProperty }, + { "NiSpecularProperty", &construct , RC_NiSpecularProperty }, + { "NiStencilProperty", &construct , RC_NiStencilProperty }, + { "NiVisController", &construct , RC_NiVisController }, + { "NiGeomMorpherController", &construct , RC_NiGeomMorpherController }, + { "NiKeyframeController", &construct , RC_NiKeyframeController }, + { "NiAlphaController", &construct , RC_NiAlphaController }, + { "NiUVController", &construct , RC_NiUVController }, + { "NiPathController", &construct , RC_NiPathController }, + { "NiMaterialColorController", &construct , RC_NiMaterialColorController }, + { "NiBSPArrayController", &construct , RC_NiBSPArrayController }, + { "NiParticleSystemController", &construct , RC_NiParticleSystemController }, + { "NiAmbientLight", &construct , RC_NiLight }, + { "NiDirectionalLight", &construct , RC_NiLight }, + { "NiTextureEffect", &construct , RC_NiTextureEffect }, + { "NiVertWeightsExtraData", &construct , RC_NiVertWeightsExtraData }, + { "NiTextKeyExtraData", &construct , RC_NiTextKeyExtraData }, + { "NiStringExtraData", &construct , RC_NiStringExtraData }, + { "NiGravity", &construct , RC_NiGravity }, + { "NiPlanarCollider", &construct , RC_NiPlanarCollider }, + { "NiParticleGrowFade", &construct , RC_NiParticleGrowFade }, + { "NiParticleColorModifier", &construct , RC_NiParticleColorModifier }, + { "NiParticleRotation", &construct , RC_NiParticleRotation }, + { "NiFloatData", &construct , RC_NiFloatData }, + { "NiTriShapeData", &construct , RC_NiTriShapeData }, + { "NiVisData", &construct , RC_NiVisData }, + { "NiColorData", &construct , RC_NiColorData }, + { "NiPixelData", &construct , RC_NiPixelData }, + { "NiMorphData", &construct , RC_NiMorphData }, + { "NiKeyframeData", &construct , RC_NiKeyframeData }, + { "NiSkinData", &construct , RC_NiSkinData }, + { "NiUVData", &construct , RC_NiUVData }, + { "NiPosData", &construct , RC_NiPosData }, + { "NiRotatingParticlesData", &construct , RC_NiRotatingParticlesData }, + { "NiAutoNormalParticlesData", &construct , RC_NiAutoNormalParticlesData }, + { "NiSequenceStreamHelper", &construct , RC_NiSequenceStreamHelper }, + { "NiSourceTexture", &construct , RC_NiSourceTexture }, + { "NiSkinInstance", &construct , RC_NiSkinInstance }, +}; + +static RecordFactoryEntry const * recordFactories_begin = &recordFactories [0]; +static RecordFactoryEntry const * recordFactories_end = &recordFactories [sizeof (recordFactories) / sizeof (recordFactories[0])]; + +RecordFactoryEntry const * lookupRecordFactory (char const * name) +{ + RecordFactoryEntry const * i; + + for (i = recordFactories_begin; i != recordFactories_end; ++i) + if (strcmp (name, i->mName) == 0) + break; + + if (i == recordFactories_end) + return NULL; + + return i; +} + /* This file implements functions from the NIFFile class. It is also where we stash all the functions we couldn't add as inline definitions in the record types. @@ -223,88 +318,15 @@ void NIFFile::parse() std::string rec = nif.getString(); - /* These are all the record types we know how to read. + RecordFactoryEntry const * entry = lookupRecordFactory (rec.c_str ()); - This can be heavily optimized later if needed. For example, a - hash table or a FSM-based parser could be used to look up - node names. - */ - - // NiNodes - if(rec == "NiNode" || rec == "AvoidNode" || - rec == "NiBSParticleNode" || - rec == "NiBSAnimationNode" || - rec == "NiBillboardNode") { r = new NiNode; r->recType = RC_NiNode; } - - // Other nodes - else if(rec == "NiTriShape") { r = new NiTriShape; r->recType = RC_NiTriShape; } - else if(rec == "NiRotatingParticles") { r = new NiRotatingParticles; r->recType = RC_NiRotatingParticles; } - else if(rec == "NiAutoNormalParticles") { r = new NiAutoNormalParticles; r->recType = RC_NiAutoNormalParticles; } - else if(rec == "NiCamera") { r = new NiCamera; r->recType = RC_NiCamera; } - else if(rec == "RootCollisionNode"){ r = new NiNode; r->recType = RC_RootCollisionNode; }// a root collision node is exactly like a node - //that's why there is no need to create a new type - - // Properties - else if(rec == "NiTexturingProperty") { r = new NiTexturingProperty; r->recType = RC_NiTexturingProperty; } - else if(rec == "NiMaterialProperty") { r = new NiMaterialProperty; r->recType = RC_NiMaterialProperty; } - else if(rec == "NiZBufferProperty") { r = new NiZBufferProperty; r->recType = RC_NiZBufferProperty; } - else if(rec == "NiAlphaProperty") { r = new NiAlphaProperty; r->recType = RC_NiAlphaProperty; } - else if(rec == "NiVertexColorProperty") { r = new NiVertexColorProperty; r->recType = RC_NiVertexColorProperty; } - else if(rec == "NiShadeProperty") { r = new NiShadeProperty; r->recType = RC_NiShadeProperty; } - else if(rec == "NiDitherProperty") { r = new NiDitherProperty; r->recType = RC_NiDitherProperty; } - else if(rec == "NiWireframeProperty") { r = new NiWireframeProperty; r->recType = RC_NiWireframeProperty; } - else if(rec == "NiSpecularProperty") { r = new NiSpecularProperty; r->recType = RC_NiSpecularProperty; } - else if(rec == "NiStencilProperty") { r = new NiStencilProperty; r->recType = RC_NiStencilProperty; } - - // Controllers - else if(rec == "NiVisController") { r = new NiVisController; r->recType = RC_NiVisController; } - else if(rec == "NiGeomMorpherController") { r = new NiGeomMorpherController; r->recType = RC_NiGeomMorpherController; } - else if(rec == "NiKeyframeController") { r = new NiKeyframeController; r->recType = RC_NiKeyframeController; } - else if(rec == "NiAlphaController") { r = new NiAlphaController; r->recType = RC_NiAlphaController; } - else if(rec == "NiUVController") { r = new NiUVController; r->recType = RC_NiUVController; } - else if(rec == "NiPathController") { r = new NiPathController; r->recType = RC_NiPathController; } - else if(rec == "NiMaterialColorController") { r = new NiMaterialColorController; r->recType = RC_NiMaterialColorController; } - else if(rec == "NiBSPArrayController") { r = new NiBSPArrayController; r->recType = RC_NiBSPArrayController; } - else if(rec == "NiParticleSystemController") { r = new NiParticleSystemController; r->recType = RC_NiParticleSystemController; } - - // Effects - else if(rec == "NiAmbientLight" || - rec == "NiDirectionalLight") { r = new NiLight; r->recType = RC_NiLight; } - else if(rec == "NiTextureEffect") { r = new NiTextureEffect; r->recType = RC_NiTextureEffect; } - - // Extra Data - else if(rec == "NiVertWeightsExtraData") { r = new NiVertWeightsExtraData; r->recType = RC_NiVertWeightsExtraData; } - else if(rec == "NiTextKeyExtraData") { r = new NiTextKeyExtraData; r->recType = RC_NiTextKeyExtraData; } - else if(rec == "NiStringExtraData") { r = new NiStringExtraData; r->recType = RC_NiStringExtraData; } - - else if(rec == "NiGravity") { r = new NiGravity; r->recType = RC_NiGravity; } - else if(rec == "NiPlanarCollider") { r = new NiPlanarCollider; r->recType = RC_NiPlanarCollider; } - else if(rec == "NiParticleGrowFade") { r = new NiParticleGrowFade; r->recType = RC_NiParticleGrowFade; } - else if(rec == "NiParticleColorModifier") { r = new NiParticleColorModifier; r->recType = RC_NiParticleColorModifier; } - else if(rec == "NiParticleRotation") { r = new NiParticleRotation; r->recType = RC_NiParticleRotation; } - - // Data - else if(rec == "NiFloatData") { r = new NiFloatData; r->recType = RC_NiFloatData; } - else if(rec == "NiTriShapeData") { r = new NiTriShapeData; r->recType = RC_NiTriShapeData; } - else if(rec == "NiVisData") { r = new NiVisData; r->recType = RC_NiVisData; } - else if(rec == "NiColorData") { r = new NiColorData; r->recType = RC_NiColorData; } - else if(rec == "NiPixelData") { r = new NiPixelData; r->recType = RC_NiPixelData; } - else if(rec == "NiMorphData") { r = new NiMorphData; r->recType = RC_NiMorphData; } - else if(rec == "NiKeyframeData") { r = new NiKeyframeData; r->recType = RC_NiKeyframeData; } - else if(rec == "NiSkinData") { r = new NiSkinData; r->recType = RC_NiSkinData; } - else if(rec == "NiUVData") { r = new NiUVData; r->recType = RC_NiUVData; } - else if(rec == "NiPosData") { r = new NiPosData; r->recType = RC_NiPosData; } - else if(rec == "NiRotatingParticlesData") { r = new NiRotatingParticlesData; r->recType = RC_NiRotatingParticlesData; } - else if(rec == "NiAutoNormalParticlesData") { r = new NiAutoNormalParticlesData; r->recType = RC_NiAutoNormalParticlesData; } - - // Other - else if(rec == "NiSequenceStreamHelper") { r = new NiSequenceStreamHelper; r->recType = RC_NiSequenceStreamHelper; } - else if(rec == "NiSourceTexture") { r = new NiSourceTexture; r->recType = RC_NiSourceTexture; } - else if(rec == "NiSkinInstance") { r = new NiSkinInstance; r->recType = RC_NiSkinInstance; } - - // Failure + if (entry != NULL) + { + r = entry->mCreate (); + r->recType = entry->mType; + } else - fail("Unknown record type " + rec); + fail("Unknown record type " + rec); assert(r != NULL); assert(r->recType != RC_MISSING); From d3c1f5e7b23bcfb30fb418b9f0acb18bcfa273a9 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 24 Feb 2013 13:51:56 -0800 Subject: [PATCH 0557/1483] renamed low-level NIF related files and include guards to conform to naming convention --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 2 +- components/CMakeLists.txt | 2 +- components/nif/controlled.hpp | 4 ++-- components/nif/controller.hpp | 8 ++++---- components/nif/data.hpp | 4 ++-- components/nif/effect.hpp | 4 ++-- components/nif/extra.hpp | 8 ++++---- components/nif/{nif_file.cpp => niffile.cpp} | 2 +- components/nif/{nif_file.hpp => niffile.hpp} | 8 ++++---- components/nif/{nif_stream.hpp => nifstream.hpp} | 4 ++-- components/nif/{nif_types.hpp => niftypes.hpp} | 4 ++-- components/nif/node.hpp | 4 ++-- components/nif/property.hpp | 4 ++-- components/nif/record.hpp | 4 ++-- components/nif/{record_ptr.hpp => recordptr.hpp} | 6 +++--- components/nifbullet/bullet_nif_loader.cpp | 2 +- 17 files changed, 36 insertions(+), 36 deletions(-) rename components/nif/{nif_file.cpp => niffile.cpp} (99%) rename components/nif/{nif_file.hpp => niffile.hpp} (97%) rename components/nif/{nif_stream.hpp => nifstream.hpp} (97%) rename components/nif/{nif_types.hpp => niftypes.hpp} (93%) rename components/nif/{record_ptr.hpp => recordptr.hpp} (97%) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d14696cdd6..a69dc7402a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ecf783d6c4..35024b3079 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,6 +1,6 @@ #include "scene.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" /// FIXME diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00342e2ac8..a80afdd6b0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -15,7 +15,7 @@ add_component_dir (bsa ) add_component_dir (nif - controlled effect nif_types record controller extra node record_ptr data nif_file property + controlled effect niftypes record controller extra node record_ptr data niffile property ) add_component_dir (nifogre diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index dac541b2d0..36c9a82ace 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_CONTROLLED_H_ -#define _NIF_CONTROLLED_H_ +#ifndef OPENMW_COMPONENTS_NIF_CONTROLLED_HPP +#define OPENMW_COMPONENTS_NIF_CONTROLLED_HPP #include "extra.hpp" #include "controller.hpp" diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 4f7ef3c0f7..8331b93b7d 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -21,12 +21,12 @@ */ -#ifndef _NIF_CONTROLLER_H_ -#define _NIF_CONTROLLER_H_ +#ifndef OPENMW_COMPONENTS_NIF_CONTROLLER_HPP +#define OPENMW_COMPONENTS_NIF_CONTROLLER_HPP #include "record.hpp" -#include "nif_file.hpp" -#include "record_ptr.hpp" +#include "niffile.hpp" +#include "recordptr.hpp" namespace Nif { diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 5f18800f0b..9bdba63961 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_DATA_H_ -#define _NIF_DATA_H_ +#ifndef OPENMW_COMPONENTS_NIF_DATA_HPP +#define OPENMW_COMPONENTS_NIF_DATA_HPP #include "controlled.hpp" diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index b07a39303c..cc1b0f41c1 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_EFFECT_H_ -#define _NIF_EFFECT_H_ +#ifndef OPENMW_COMPONENTS_NIF_EFFECT_HPP +#define OPENMW_COMPONENTS_NIF_EFFECT_HPP #include "node.hpp" diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index b5335f9871..45c4fefc69 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -21,12 +21,12 @@ */ -#ifndef _NIF_EXTRA_H_ -#define _NIF_EXTRA_H_ +#ifndef OPENMW_COMPONENTS_NIF_EXTRA_HPP +#define OPENMW_COMPONENTS_NIF_EXTRA_HPP #include "record.hpp" -#include "nif_file.hpp" -#include "record_ptr.hpp" +#include "niffile.hpp" +#include "recordptr.hpp" namespace Nif { diff --git a/components/nif/nif_file.cpp b/components/nif/niffile.cpp similarity index 99% rename from components/nif/nif_file.cpp rename to components/nif/niffile.cpp index dc8670cba2..bf05e7576a 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/niffile.cpp @@ -21,7 +21,7 @@ */ -#include "nif_file.hpp" +#include "niffile.hpp" #include "record.hpp" #include "components/misc/stringops.hpp" diff --git a/components/nif/nif_file.hpp b/components/nif/niffile.hpp similarity index 97% rename from components/nif/nif_file.hpp rename to components/nif/niffile.hpp index a406de4a0c..ed11bdd7cb 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/niffile.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_FILE_H_ -#define _NIF_FILE_H_ +#ifndef OPENMW_COMPONENTS_NIF_NIFFILE_HPP +#define OPENMW_COMPONENTS_NIF_NIFFILE_HPP #include #include @@ -45,8 +45,8 @@ #include #include "record.hpp" -#include "nif_types.hpp" -#include "nif_stream.hpp" +#include "niftypes.hpp" +#include "nifstream.hpp" namespace Nif { diff --git a/components/nif/nif_stream.hpp b/components/nif/nifstream.hpp similarity index 97% rename from components/nif/nif_stream.hpp rename to components/nif/nifstream.hpp index 8fb98f3d65..02b931b7ed 100644 --- a/components/nif/nif_stream.hpp +++ b/components/nif/nifstream.hpp @@ -1,5 +1,5 @@ -#ifndef _NIF_STREAM_HPP_ -#define _NIF_STREAM_HPP_ +#ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP +#define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP namespace Nif { diff --git a/components/nif/nif_types.hpp b/components/nif/niftypes.hpp similarity index 93% rename from components/nif/nif_types.hpp rename to components/nif/niftypes.hpp index a5fb613617..786c48b65e 100644 --- a/components/nif/nif_types.hpp +++ b/components/nif/niftypes.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_TYPES_H_ -#define _NIF_TYPES_H_ +#ifndef OPENMW_COMPONENTS_NIF_NIFTYPES_HPP +#define OPENMW_COMPONENTS_NIF_NIFTYPES_HPP #include #include diff --git a/components/nif/node.hpp b/components/nif/node.hpp index e087037565..ab92d74f8d 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_NODE_H_ -#define _NIF_NODE_H_ +#ifndef OPENMW_COMPONENTS_NIF_NODE_HPP +#define OPENMW_COMPONENTS_NIF_NODE_HPP #include diff --git a/components/nif/property.hpp b/components/nif/property.hpp index cdf97986c3..cd1e0a5d11 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_PROPERTY_H_ -#define _NIF_PROPERTY_H_ +#ifndef OPENMW_COMPONENTS_NIF_PROPERTY_HPP +#define OPENMW_COMPONENTS_NIF_PROPERTY_HPP #include "controlled.hpp" diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 9f0645dfdf..3a3cd9b84a 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_RECORD_H_ -#define _NIF_RECORD_H_ +#ifndef OPENMW_COMPONENTS_NIF_RECORD_HPP +#define OPENMW_COMPONENTS_NIF_RECORD_HPP #include diff --git a/components/nif/record_ptr.hpp b/components/nif/recordptr.hpp similarity index 97% rename from components/nif/record_ptr.hpp rename to components/nif/recordptr.hpp index 855099a04a..c5bafea124 100644 --- a/components/nif/record_ptr.hpp +++ b/components/nif/recordptr.hpp @@ -21,10 +21,10 @@ */ -#ifndef _NIF_RECORD_PTR_H_ -#define _NIF_RECORD_PTR_H_ +#ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP +#define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP -#include "nif_file.hpp" +#include "niffile.hpp" #include namespace Nif diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 3d9c16ebbf..e337542646 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -25,7 +25,7 @@ http://www.gnu.org/licenses/ . #include #include -#include "../nif/nif_file.hpp" +#include "../nif/niffile.hpp" #include "../nif/node.hpp" #include "../nif/data.hpp" #include "../nif/property.hpp" From bf6c855e6d829ca2f54abc380f6653cb0a5e3626 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 2 Mar 2013 12:49:26 -0600 Subject: [PATCH 0558/1483] Final changes to implement save-on-close features --- apps/opencs/view/doc/view.cpp | 9 +++--- apps/opencs/view/doc/viewmanager.cpp | 41 +++++++++++++++------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index fea121aa0d..0a8759fa1f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -18,14 +18,10 @@ #include "operations.hpp" #include "subview.hpp" -#include void CSVDoc::View::closeEvent (QCloseEvent *event) { if (!mViewManager.closeRequest (this)) - { - qDebug() << "ignoring event"; event->ignore(); - } } void CSVDoc::View::setupFileMenu() @@ -43,6 +39,11 @@ void CSVDoc::View::setupFileMenu() mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); + + QAction *exit = new QAction (tr ("&Exit"), this); + connect (exit, SIGNAL (triggered()), this, SLOT (close())); + file->addAction(exit); + } void CSVDoc::View::setupEditMenu() diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 02407dfcde..a5c7910c0f 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -12,7 +12,6 @@ #include "view.hpp" -#include #include @@ -105,15 +104,13 @@ bool CSVDoc::ViewManager::closeRequest (View *view) CSMDoc::Document *document = view->getDocument(); - //notify user of unsaved changes and process response - if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (view); - //notify user of saving in progress if ( document->getState() & CSMDoc::State_Saving ) continueWithClose = showSaveInProgressMessageBox (view); - - qDebug() << "Continue with close? " << continueWithClose; + else + //notify user of unsaved changes and process response + if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (view); if (continueWithClose) { @@ -144,8 +141,13 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) { case QMessageBox::Save: view->getDocument()->save(); - mCloseMeOnSaveStateChange = view; - retVal = false; + + retVal = !(view->getDocument()->getState() & CSMDoc::State_Saving); + + if (!retVal) + mCloseMeOnSaveStateChange = view; + else + mCloseMeOnSaveStateChange = 0; break; case QMessageBox::Discard: @@ -181,8 +183,16 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (View* view) break; case QMessageBox::No: //shutdown after save completes + + //return true (continue with close) if the save operation ended before the + //user clicked "No" + retVal = !(view->getDocument()->getState() & CSMDoc::State_Saving); + + if (!retVal) mCloseMeOnSaveStateChange = view; - retVal = false; + else + mCloseMeOnSaveStateChange = 0; + break; case QMessageBox::Cancel: //abort shutdown, allow save to complete @@ -203,17 +213,10 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc if ((*iter)->getDocument()==document) (*iter)->updateDocumentState(); - if (mPreviousDocumentState & CSMDoc::State_Saving) - qDebug() << "Last state was saving"; - else - qDebug() << "Last state was something else"; - //mechanism to shutdown main window after saving operation completes if (mCloseMeOnSaveStateChange && (mPreviousDocumentState & CSMDoc::State_Saving)) - { - mCloseMeOnSaveStateChange->close(); - mCloseMeOnSaveStateChange = 0; - } + if (mCloseMeOnSaveStateChange->close()) + mCloseMeOnSaveStateChange = 0; mPreviousDocumentState = state; } From fdfcd5bb4774e6a03fef5afafc5f116a635015cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 12:23:29 -0800 Subject: [PATCH 0559/1483] Material properties are accumulative along the node tree --- components/nifogre/ogre_nif_loader.cpp | 101 +++++++++++++------------ 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index d33243dd47..1d9c4d7481 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -549,7 +549,10 @@ static void fail(const std::string &msg) public: -static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group) +static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -568,36 +571,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String bool vertexColour = (shape->data->colors.size() != 0); - // These are set below if present - const Nif::NiTexturingProperty *t = NULL; - const Nif::NiMaterialProperty *m = NULL; - const Nif::NiAlphaProperty *a = NULL; - - // Scan the property list for material information - const Nif::PropertyList &list = shape->props; - for (size_t i = 0;i < list.length();i++) - { - // Entries may be empty - if (list[i].empty()) continue; - - const Nif::Property *pr = list[i].getPtr(); - if (pr->recType == Nif::RC_NiTexturingProperty) - t = static_cast(pr); - else if (pr->recType == Nif::RC_NiMaterialProperty) - m = static_cast(pr); - else if (pr->recType == Nif::RC_NiAlphaProperty) - a = static_cast(pr); - else if (pr->recType == Nif::RC_NiStencilProperty) - /* unused */; - else - warn("Skipped property type: "+pr->recName); - } - // Texture - if (t && t->textures[0].inUse) + if(texprop && texprop->textures[0].inUse) { - Nif::NiSourceTexture *st = t->textures[0].texture.getPtr(); - if (st->external) + const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); + if(st->external) { /* Bethesda at some point converted all their BSA * textures from tga to dds for increased load speed, but all @@ -633,25 +611,25 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String } // Alpha modifiers - if (a) + if(alphaprop) { - alphaFlags = a->flags; - alphaTest = a->data.threshold; + alphaFlags = alphaprop->flags; + alphaTest = alphaprop->data.threshold; } // Material - if(m) + if(matprop) { - ambient = m->data.ambient; - diffuse = m->data.diffuse; - specular = m->data.specular; - emissive = m->data.emissive; - glossiness = m->data.glossiness; - alpha = m->data.alpha; + ambient = matprop->data.ambient; + diffuse = matprop->data.diffuse; + specular = matprop->data.specular; + emissive = matprop->data.emissive; + glossiness = matprop->data.glossiness; + alpha = matprop->data.alpha; } Ogre::String matname = name; - if (m || !texName.empty()) + if(matprop || !texName.empty()) { // Generate a hash out of all properties that can affect the material. size_t h = 0; @@ -749,7 +727,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mName; std::string mGroup; size_t mShapeIndex; - std::string mMaterialName; void warn(const std::string &msg) { @@ -764,7 +741,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape, + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -962,15 +942,39 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - if(mMaterialName.length() > 0) - sub->setMaterialName(mMaterialName); + std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, + texprop, matprop, alphaprop); + if(matname.length() > 0) + sub->setMaterialName(matname); } - bool findTriShape(Ogre::Mesh *mesh, Nif::Node const *node) + bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, + const Nif::NiTexturingProperty *texprop=NULL, + const Nif::NiMaterialProperty *matprop=NULL, + const Nif::NiAlphaProperty *alphaprop=NULL) { + // Scan the property list for material information + const Nif::PropertyList &proplist = node->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node)); + handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop); return true; } @@ -982,7 +986,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr())) + if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop)) return true; } } @@ -1015,7 +1019,7 @@ public: return; } - Nif::Node const *node = dynamic_cast(nif->getRecord(mShapeIndex)); + const Nif::Node *node = dynamic_cast(nif->getRecord(0)); findTriShape(mesh, node); } @@ -1066,7 +1070,6 @@ public: NIFMeshLoader *loader = &sLoaders[fullname]; *loader = *this; loader->mShapeIndex = shape->recIndex; - loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); From dde43e8c87430c98e52e4aa88186a57ebdde9620 Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 2 Mar 2013 21:46:31 +0100 Subject: [PATCH 0560/1483] Some cleanup --- apps/openmw/mwworld/store.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 52120ed0ec..586e407ff0 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,11 +187,11 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); - // delete from static part of shared - typename std::vector::iterator sharedit = mShared.begin(); - for (; sharedit != (mShared.begin()+mStatic.size()); ++sharedit) { - if((*sharedit)->mId == item.mId) { - mShared.erase(sharedit); + // delete from the static part of mShared + typename std::vector::iterator sharedIter = mShared.begin(); + for (; sharedIter != (mShared.begin()+mStatic.size()); ++sharedIter) { + if((*sharedIter)->mId == item.mId) { + mShared.erase(sharedIter); break; } } From 109dff2d29f1ed3b71c4169f917f390043278b46 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 24 Feb 2013 13:52:23 -0800 Subject: [PATCH 0561/1483] renamed high level NIF files... --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 2 +- components/CMakeLists.txt | 4 ++-- .../nifbullet/{bullet_nif_loader.cpp => bulletnifloader.cpp} | 2 +- .../nifbullet/{bullet_nif_loader.hpp => bulletnifloader.hpp} | 4 ++-- components/nifogre/{ogre_nif_loader.cpp => ogrenifloader.cpp} | 2 +- components/nifogre/{ogre_nif_loader.hpp => ogrenifloader.hpp} | 4 ++-- components/nifoverrides/nifoverrides.hpp | 4 ++-- libs/openengine/bullet/CMotionState.cpp | 2 +- libs/openengine/bullet/physic.cpp | 2 +- 13 files changed, 18 insertions(+), 18 deletions(-) rename components/nifbullet/{bullet_nif_loader.cpp => bulletnifloader.cpp} (99%) rename components/nifbullet/{bullet_nif_loader.hpp => bulletnifloader.hpp} (96%) rename components/nifogre/{ogre_nif_loader.cpp => ogrenifloader.cpp} (99%) rename components/nifogre/{ogre_nif_loader.hpp => ogrenifloader.hpp} (96%) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a69dc7402a..74e967d8d0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include #include "mwinput/inputmanagerimp.hpp" diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 810ca869f5..7caf351694 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,7 +1,7 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H -#include +#include #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index e91180a42c..89425e9f21 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0620796931..0f778511d6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -14,7 +14,7 @@ #include -#include +#include #include diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 65cbc1164e..566a463b6b 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include //#include "../mwbase/world.hpp" // FIXME #include "../mwbase/environment.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a80afdd6b0..9fdc728731 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,11 +19,11 @@ add_component_dir (nif ) add_component_dir (nifogre - ogre_nif_loader + ogrenifloader ) add_component_dir (nifbullet - bullet_nif_loader + bulletnifloader ) add_component_dir (to_utf8 diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bulletnifloader.cpp similarity index 99% rename from components/nifbullet/bullet_nif_loader.cpp rename to components/nifbullet/bulletnifloader.cpp index e337542646..91fd6dbcfa 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -21,7 +21,7 @@ http://www.gnu.org/licenses/ . */ -#include "bullet_nif_loader.hpp" +#include "bulletnifloader.hpp" #include #include diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bulletnifloader.hpp similarity index 96% rename from components/nifbullet/bullet_nif_loader.hpp rename to components/nifbullet/bulletnifloader.hpp index 0629b208de..0ff4b4ccd7 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -21,8 +21,8 @@ */ -#ifndef _BULLET_NIF_LOADER_H_ -#define _BULLET_NIF_LOADER_H_ +#ifndef OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP +#define OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP #include #include diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogrenifloader.cpp similarity index 99% rename from components/nifogre/ogre_nif_loader.cpp rename to components/nifogre/ogrenifloader.cpp index d33243dd47..4eaedeaa84 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -21,7 +21,7 @@ */ -#include "ogre_nif_loader.hpp" +#include "ogrenifloader.hpp" #include diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogrenifloader.hpp similarity index 96% rename from components/nifogre/ogre_nif_loader.hpp rename to components/nifogre/ogrenifloader.hpp index eae37dd8a9..b8b2e3c007 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -21,8 +21,8 @@ */ -#ifndef _OGRE_NIF_LOADER_H_ -#define _OGRE_NIF_LOADER_H_ +#ifndef OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP +#define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP #include #include diff --git a/components/nifoverrides/nifoverrides.hpp b/components/nifoverrides/nifoverrides.hpp index c9b711df67..ba2e4cc3c3 100644 --- a/components/nifoverrides/nifoverrides.hpp +++ b/components/nifoverrides/nifoverrides.hpp @@ -1,5 +1,5 @@ -#ifndef COMPONENTS_NIFOVERRIDES_H -#define COMPONENTS_NIFOVERRIDES_H +#ifndef OPENMW_COMPONENTS_NIFOVERRIDES_NIFOVERRIDES_HPP +#define OPENMW_COMPONENTS_NIFOVERRIDES_NIFOVERRIDES_HPP #include diff --git a/libs/openengine/bullet/CMotionState.cpp b/libs/openengine/bullet/CMotionState.cpp index 6be615dfb0..c20415884a 100644 --- a/libs/openengine/bullet/CMotionState.cpp +++ b/libs/openengine/bullet/CMotionState.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace OEngine { namespace Physic diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index f993ce68e2..119f6893a3 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include "CMotionState.h" #include "OgreRoot.h" #include "btKinematicCharacterController.h" From 2b6bb9657bd46d2c2a5509a019647bcaa12dc7bb Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sat, 2 Mar 2013 23:49:31 +0100 Subject: [PATCH 0562/1483] Added Qt Designer .ui files --- apps/launcher/CMakeLists.txt | 10 +- apps/launcher/ui/graphicspage.ui | 134 +++++++++++++++++++++++ apps/launcher/ui/mainwindow.ui | 80 ++++++++++++++ apps/launcher/ui/playpage.ui | 180 +++++++++++++++++++++++++++++++ 4 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 apps/launcher/ui/graphicspage.ui create mode 100644 apps/launcher/ui/mainwindow.ui create mode 100644 apps/launcher/ui/playpage.ui diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index b2e6c70098..bc39690972 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -53,7 +53,13 @@ set(LAUNCHER_HEADER_MOC utils/textinputdialog.hpp ) -source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) +set(LAUNCHER_UI + ui/graphicspage.ui + ui/mainwindow.ui + ui/playpage.ui +) + +source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) find_package(Qt4 REQUIRED) set(QT_USE_QTGUI 1) @@ -66,6 +72,7 @@ endif(WIN32) QT4_ADD_RESOURCES(RCC_SRCS resources.qrc) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) +QT4_WRAP_UI(UI_HDRS ${LAUCHER_UI}) include(${QT_USE_FILE}) @@ -85,6 +92,7 @@ add_executable(omwlauncher ${LAUNCHER_HEADER} ${RCC_SRCS} ${MOC_SRCS} + ${UI_HDRS} ) target_link_libraries(omwlauncher diff --git a/apps/launcher/ui/graphicspage.ui b/apps/launcher/ui/graphicspage.ui new file mode 100644 index 0000000000..670b4f9c63 --- /dev/null +++ b/apps/launcher/ui/graphicspage.ui @@ -0,0 +1,134 @@ + + + graphicsPage + + + + 0 + 0 + 400 + 300 + + + + + + + Render System + + + + + + Rendering Subsystem: + + + + + + + + + + + + + GroupBox + + + + + + Vertical Sync + + + + + + + Full Screen + + + + + + + Anti-aliasing: + + + + + + + Resolution: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + Custom: + + + + + + + Standard: + + + true + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 61 + + + + + + + + + diff --git a/apps/launcher/ui/mainwindow.ui b/apps/launcher/ui/mainwindow.ui new file mode 100644 index 0000000000..4e1a7854d6 --- /dev/null +++ b/apps/launcher/ui/mainwindow.ui @@ -0,0 +1,80 @@ + + + MainWindow + + + + 0 + 0 + 575 + 575 + + + + + 575 + 575 + + + + OpenMW Launcher + + + + :/images/openmw.png:/images/openmw.png + + + + + + + + 400 + 80 + + + + + 16777215 + 80 + + + + #iconWidget { + background-image: url(":/images/openmw-header.png"); + background-color: white; + background-repeat: no-repeat; + background-attachment: scroll; + background-position: right; +} + + + + + + + + + + + + + + + + + + + + QDialogButtonBox::Close + + + + + + + + + + + diff --git a/apps/launcher/ui/playpage.ui b/apps/launcher/ui/playpage.ui new file mode 100644 index 0000000000..86a763f648 --- /dev/null +++ b/apps/launcher/ui/playpage.ui @@ -0,0 +1,180 @@ + + + playPage + + + #playPage { + background-image: url(":/images/playpage-background.png"); + background-repeat: no-repeat; + background-position: top; +} + + + + + 30 + + + 100 + + + 30 + + + + + + 200 + 85 + + + + + 200 + 85 + + + + #playButton { + height: 50px; + margin-bottom: 30px; + + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(255, 255, 255, 200), + stop:0.1 rgba(255, 255, 255, 15), + stop:0.49 rgba(255, 255, 255, 75), + stop:0.5 rgba(0, 0, 0, 0), + stop:0.9 rgba(0, 0, 0, 55), + stop:1 rgba(0, 0, 0, 100)); + + font-size: 26pt; + font-family: "EB Garamond", "EB Garamond 08"; + color: black; + + border-right: 1px solid rgba(0, 0, 0, 155); + border-left: 1px solid rgba(0, 0, 0, 55); + border-top: 1px solid rgba(0, 0, 0, 55); + border-bottom: 1px solid rgba(0, 0, 0, 155); + + border-radius: 5px; +} + +#playButton:hover { + border-bottom: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-top: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-right: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-left: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-width: 2px; + border-style: solid; +} + +#playButton:pressed { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(0, 0, 0, 75), + stop:0.1 rgba(0, 0, 0, 15), + stop:0.2 rgba(255, 255, 255, 55) + stop:0.95 rgba(255, 255, 255, 55), + stop:1 rgba(255, 255, 255, 155)); + + border: 1px solid rgba(0, 0, 0, 55); +} + + + Play + + + + + + + #profileLabel { + font-size: 18pt; + font-family: "EB Garamond", "EB Garamond 08"; +} + + + + Current Profile: + + + + + + + #profilesComboBox { + padding: 1px 18px 1px 3px; + + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 white, stop:0.2 rgba(0, 0, 0, 25), stop:1 white); + border-width: 1px; + border-color: rgba(0, 0, 0, 125); + border-style: solid; + border-radius: 2px; +} + +/*QComboBox gets the "on" state when the popup is open */ +#profilesComboBox:!editable:on, #ProfilesComboBox::drop-down:editable:on { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(0, 0, 0, 75), + stop:0.1 rgba(0, 0, 0, 15), + stop:0.2 rgba(255, 255, 255, 55)); + + border: 1px solid rgba(0, 0, 0, 55); +} + +#profilesComboBox { /* shift the text when the popup opens */ + padding-top: 3px; + padding-left: 4px; + + font-size: 12pt; + font-family: "EB Garamond", "EB Garamond 08"; +} + +#profilesComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + + border-width: 1px; + border-left-width: 1px; + border-left-color: darkgray; + border-left-style: solid; /* just a single line */ + border-top-right-radius: 3px; /* same radius as the QComboBox */ + border-bottom-right-radius: 3px; +} + +#profilesComboBox::down-arrow { + image: url(":/images/down.png"); +} + +#profilesComboBox::down-arrow:on { /* shift the arrow when popup is open */ + top: 1px; + left: 1px; +} + +#profilesComboBox QAbstractItemView { + border: 2px solid lightgray; + border-radius: 5px; +} + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + From f2193bb1bacde7fe5c37475cab839c3f2e08374f Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 3 Mar 2013 00:48:09 +0100 Subject: [PATCH 0563/1483] Made the mainwindow use a .ui file and removed the stylesheet --- CMakeLists.txt | 6 -- apps/launcher/CMakeLists.txt | 22 ++----- apps/launcher/maindialog.cpp | 92 +++++++------------------- apps/launcher/maindialog.hpp | 8 ++- files/launcher.qss | 123 ----------------------------------- 5 files changed, 35 insertions(+), 216 deletions(-) delete mode 100644 files/launcher.qss diff --git a/CMakeLists.txt b/CMakeLists.txt index e583f23d44..6498e723c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -379,7 +379,6 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/OFL.txt" "${OpenMW_SOURCE_DIR}/DejaVu Font License.txt" "${OpenMW_SOURCE_DIR}/Daedric Font License.txt" - "${OpenMW_BINARY_DIR}/launcher.qss" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" @@ -566,8 +565,6 @@ if (APPLE) install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) @@ -681,7 +678,4 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) # Install resources INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) - IF(BUILD_LAUNCHER) - INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) - ENDIF(BUILD_LAUNCHER) endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index bc39690972..206e94794e 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -36,6 +36,7 @@ set(LAUNCHER_HEADER utils/comboboxlineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp + ) # Headers that must be pre-processed @@ -54,9 +55,9 @@ set(LAUNCHER_HEADER_MOC ) set(LAUNCHER_UI - ui/graphicspage.ui - ui/mainwindow.ui - ui/playpage.ui + ./ui/graphicspage.ui + ./ui/mainwindow.ui + ./ui/playpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) @@ -72,9 +73,10 @@ endif(WIN32) QT4_ADD_RESOURCES(RCC_SRCS resources.qrc) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) -QT4_WRAP_UI(UI_HDRS ${LAUCHER_UI}) +QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) include(${QT_USE_FILE}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) # Main executable IF(OGRE_STATIC) @@ -107,18 +109,6 @@ if(DPKG_PROGRAM) INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher) endif() -if (APPLE) - configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss - "${APP_BUNDLE_DIR}/../launcher.qss") -else() - configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss - "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources/launcher.qss") - - # Fallback in case getGlobalDataPath does not point to resources - configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss - "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss") -endif() - if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(omwlauncher gcov) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index e69f134d29..f438e64c9a 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -12,46 +12,6 @@ MainDialog::MainDialog() : mGameSettings(mCfgMgr) { - QWidget *centralWidget = new QWidget(this); - setCentralWidget(centralWidget); - - mIconWidget = new QListWidget(centralWidget); - mIconWidget->setObjectName("IconWidget"); - mIconWidget->setViewMode(QListView::IconMode); - mIconWidget->setWrapping(false); - mIconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure - mIconWidget->setIconSize(QSize(48, 48)); - mIconWidget->setMovement(QListView::Static); - - mIconWidget->setMinimumWidth(400); - mIconWidget->setFixedHeight(80); - mIconWidget->setSpacing(4); - mIconWidget->setCurrentRow(0); - mIconWidget->setFlow(QListView::LeftToRight); - - QGroupBox *groupBox = new QGroupBox(centralWidget); - QVBoxLayout *groupLayout = new QVBoxLayout(groupBox); - - mPagesWidget = new QStackedWidget(groupBox); - groupLayout->addWidget(mPagesWidget); - - QPushButton *playButton = new QPushButton(tr("Play")); - - QDialogButtonBox *buttonBox = new QDialogButtonBox(centralWidget); - buttonBox->setStandardButtons(QDialogButtonBox::Close); - buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole); - - QVBoxLayout *dialogLayout = new QVBoxLayout(centralWidget); - dialogLayout->addWidget(mIconWidget); - dialogLayout->addWidget(groupBox); - dialogLayout->addWidget(buttonBox); - - setWindowTitle(tr("OpenMW Launcher")); - setWindowIcon(QIcon(":/images/openmw.png")); - // Remove what's this? button - setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); - setMinimumSize(QSize(575, 575)); - // Install the stylesheet font QFile file; QFontDatabase fontDatabase; @@ -71,31 +31,27 @@ MainDialog::MainDialog() fontDatabase.addApplicationFont(font); } - // Load the stylesheet - QString config = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/launcher.qss"); - file.setFileName(config); + setupUi(this); - if (!file.exists()) - file.setFileName(QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("launcher.qss")); + iconWidget->setViewMode(QListView::IconMode); + iconWidget->setWrapping(false); + iconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure + iconWidget->setIconSize(QSize(48, 48)); + iconWidget->setMovement(QListView::Static); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening Launcher stylesheet")); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - } else { - QString styleSheet = QLatin1String(file.readAll()); - qApp->setStyleSheet(styleSheet); - file.close(); - } + iconWidget->setSpacing(4); + iconWidget->setCurrentRow(0); + iconWidget->setFlow(QListView::LeftToRight); + + QPushButton *playButton = new QPushButton(tr("Play")); + buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole); connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); + // Remove what's this? button + setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); + createIcons(); } @@ -107,25 +63,25 @@ void MainDialog::createIcons() // We create a fallback icon because the default fallback doesn't work QIcon graphicsIcon = QIcon(":/icons/tango/video-display.png"); - QListWidgetItem *playButton = new QListWidgetItem(mIconWidget); + QListWidgetItem *playButton = new QListWidgetItem(iconWidget); playButton->setIcon(QIcon(":/images/openmw.png")); playButton->setText(tr("Play")); playButton->setTextAlignment(Qt::AlignCenter); playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - QListWidgetItem *graphicsButton = new QListWidgetItem(mIconWidget); + QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget); graphicsButton->setIcon(QIcon::fromTheme("video-display", graphicsIcon)); graphicsButton->setText(tr("Graphics")); graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute); graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - QListWidgetItem *dataFilesButton = new QListWidgetItem(mIconWidget); + QListWidgetItem *dataFilesButton = new QListWidgetItem(iconWidget); dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png")); dataFilesButton->setText(tr("Data Files")); dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom); dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - connect(mIconWidget, + connect(iconWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*))); @@ -142,12 +98,12 @@ void MainDialog::createPages() mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget - mPagesWidget->addWidget(mPlayPage); - mPagesWidget->addWidget(mGraphicsPage); - mPagesWidget->addWidget(mDataFilesPage); + pagesWidget->addWidget(mPlayPage); + pagesWidget->addWidget(mGraphicsPage); + pagesWidget->addWidget(mDataFilesPage); // Select the first page - mIconWidget->setCurrentItem(mIconWidget->item(0), QItemSelectionModel::Select); + iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select); connect(mPlayPage->mPlayButton, SIGNAL(clicked()), this, SLOT(play())); @@ -326,7 +282,7 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) if (!current) current = previous; - mPagesWidget->setCurrentIndex(mIconWidget->row(current)); + pagesWidget->setCurrentIndex(iconWidget->row(current)); } bool MainDialog::setupLauncherSettings() diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index f221bd5e69..780cd8beb3 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -9,6 +9,8 @@ #include "settings/graphicssettings.hpp" #include "settings/launchersettings.hpp" +#include "ui_mainwindow.h" + class QListWidget; class QListWidgetItem; class QStackedWidget; @@ -20,7 +22,7 @@ class PlayPage; class GraphicsPage; class DataFilesPage; -class MainDialog : public QMainWindow +class MainDialog : public QMainWindow, private Ui::MainWindow { Q_OBJECT @@ -56,8 +58,8 @@ private: void closeEvent(QCloseEvent *event); - QListWidget *mIconWidget; - QStackedWidget *mPagesWidget; +// QListWidget *mIconWidget; +// QStackedWidget *mPagesWidget; PlayPage *mPlayPage; GraphicsPage *mGraphicsPage; diff --git a/files/launcher.qss b/files/launcher.qss deleted file mode 100644 index 1eb056d4d3..0000000000 --- a/files/launcher.qss +++ /dev/null @@ -1,123 +0,0 @@ -#PlayGroup { - background-image: url(":/images/playpage-background.png"); - background-repeat: no-repeat; - background-position: top; - padding-left: 30px; - padding-right: 30px; -} - -#MastersWidget { - selection-background-color: palette(highlight); -} - -#PlayButton { - height: 50px; - margin-bottom: 30px; - - background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(255, 255, 255, 200), - stop:0.1 rgba(255, 255, 255, 15), - stop:0.49 rgba(255, 255, 255, 75), - stop:0.5 rgba(0, 0, 0, 0), - stop:0.9 rgba(0, 0, 0, 55), - stop:1 rgba(0, 0, 0, 100)); - - font-size: 26pt; - font-family: "EB Garamond", "EB Garamond 08"; - color: black; - - border-right: 1px solid rgba(0, 0, 0, 155); - border-left: 1px solid rgba(0, 0, 0, 55); - border-top: 1px solid rgba(0, 0, 0, 55); - border-bottom: 1px solid rgba(0, 0, 0, 155); - - border-radius: 5px; -} - -#PlayButton:hover { - border-bottom: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-top: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-right: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-left: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-width: 2px; - border-style: solid; -} - -#PlayButton:pressed { - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(0, 0, 0, 75), - stop:0.1 rgba(0, 0, 0, 15), - stop:0.2 rgba(255, 255, 255, 55) - stop:0.95 rgba(255, 255, 255, 55), - stop:1 rgba(255, 255, 255, 155)); - - border: 1px solid rgba(0, 0, 0, 55); -} - -#ProfileLabel { - font-size: 18pt; - font-family: "EB Garamond", "EB Garamond 08"; -} - -#ProfilesComboBox { - padding: 1px 18px 1px 3px; - - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 white, stop:0.2 rgba(0, 0, 0, 25), stop:1 white); - border-width: 1px; - border-color: rgba(0, 0, 0, 125); - border-style: solid; - border-radius: 2px; -} - -/*QComboBox gets the "on" state when the popup is open */ -#ProfilesComboBox:!editable:on, #ProfilesComboBox::drop-down:editable:on { - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(0, 0, 0, 75), - stop:0.1 rgba(0, 0, 0, 15), - stop:0.2 rgba(255, 255, 255, 55)); - - border: 1px solid rgba(0, 0, 0, 55); -} - - -#ProfilesComboBox { /* shift the text when the popup opens */ - padding-top: 3px; - padding-left: 4px; - - font-size: 12pt; - font-family: "EB Garamond", "EB Garamond 08"; -} - -#ProfilesComboBox::drop-down { - subcontrol-origin: padding; - subcontrol-position: top right; - - border-width: 1px; - border-left-width: 1px; - border-left-color: darkgray; - border-left-style: solid; /* just a single line */ - border-top-right-radius: 3px; /* same radius as the QComboBox */ - border-bottom-right-radius: 3px; -} - -#ProfilesComboBox::down-arrow { - image: url(":/images/down.png"); -} - -#ProfilesComboBox::down-arrow:on { /* shift the arrow when popup is open */ - top: 1px; - left: 1px; -} - -#ProfilesComboBox QAbstractItemView { - border: 2px solid lightgray; - border-radius: 5px; -} - -#IconWidget { - background-image: url(":/images/openmw-header.png"); - background-color: white; - background-repeat: no-repeat; - background-attachment: scroll; - background-position: right; -} From 03785f3ecda06bad6a8c85af8aa7490da28c9f07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 16:28:32 -0800 Subject: [PATCH 0564/1483] Handle NiVertexColorProperty --- components/nifogre/ogre_nif_loader.cpp | 61 +++++++++++++++++++------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1d9c4d7481..1d0d31961e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -552,7 +552,8 @@ public: static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop) + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -567,6 +568,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String float alpha = 1.0f; int alphaFlags = 0; int alphaTest = 0; + int vertMode = 2; + //int lightMode = 1; Ogre::String texName; bool vertexColour = (shape->data->colors.size() != 0); @@ -617,6 +620,14 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String alphaTest = alphaprop->data.threshold; } + // Vertex color handling + if(vertprop) + { + vertMode = vertprop->data.vertmode; + // FIXME: Handle lightmode? + //lightMode = vertprop->data.lightmode; + } + // Material if(matprop) { @@ -649,6 +660,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); + boost::hash_combine(h, vertMode); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -662,19 +674,31 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // No existing material like this. Create a new one. sh::MaterialInstance* instance = sh::Factory::getInstance ().createMaterialInstance (matname, "openmw_objects_base"); - instance->setProperty ("ambient", sh::makeProperty ( - new sh::Vector3(ambient.x, ambient.y, ambient.z))); + if(vertMode == 0 || !vertexColour) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, alpha))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, alpha))); + } + else if(vertMode == 1) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, alpha))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); + } + else if(vertMode == 2) + { + instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, alpha))); + } + else + std::cerr<< "Unhandled vertex mode: "<setProperty ("diffuse", sh::makeProperty ( - new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - - instance->setProperty ("specular", sh::makeProperty ( + instance->setProperty("specular", sh::makeProperty( new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); - instance->setProperty ("emissive", sh::makeProperty ( - new sh::Vector3(emissive.x, emissive.y, emissive.z))); - - instance->setProperty ("diffuseMap", sh::makeProperty(texName)); + instance->setProperty("diffuseMap", sh::makeProperty(texName)); if (vertexColour) instance->setProperty ("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); @@ -744,7 +768,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape, const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop) + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -943,7 +968,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, - texprop, matprop, alphaprop); + texprop, matprop, alphaprop, + vertprop); if(matname.length() > 0) sub->setMaterialName(matname); } @@ -951,7 +977,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, const Nif::NiTexturingProperty *texprop=NULL, const Nif::NiMaterialProperty *matprop=NULL, - const Nif::NiAlphaProperty *alphaprop=NULL) + const Nif::NiAlphaProperty *alphaprop=NULL, + const Nif::NiVertexColorProperty *vertprop=NULL) { // Scan the property list for material information const Nif::PropertyList &proplist = node->props; @@ -968,13 +995,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader matprop = static_cast(pr); else if(pr->recType == Nif::RC_NiAlphaProperty) alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop); + handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop); return true; } @@ -986,7 +1015,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop)) + if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop)) return true; } } From 0a6e3701abf08bb5804f151ab8bd4f87e31a7e90 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 3 Mar 2013 01:49:41 +0100 Subject: [PATCH 0565/1483] Made the Play page use a .ui file too --- apps/launcher/maindialog.cpp | 15 +- apps/launcher/maindialog.hpp | 9 -- apps/launcher/playpage.cpp | 58 ++++---- apps/launcher/playpage.hpp | 22 ++- apps/launcher/ui/graphicspage.ui | 4 +- apps/launcher/ui/playpage.ui | 228 ++++++++++++++++--------------- 6 files changed, 170 insertions(+), 166 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index f438e64c9a..5621b75c02 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -94,8 +94,8 @@ void MainDialog::createPages() mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage - mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); - mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); + mPlayPage->setProfilesComboBoxModel(mDataFilesPage->mProfilesComboBox->model()); + mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget pagesWidget->addWidget(mPlayPage); @@ -105,15 +105,10 @@ void MainDialog::createPages() // Select the first page iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select); - connect(mPlayPage->mPlayButton, SIGNAL(clicked()), this, SLOT(play())); + connect(mPlayPage, SIGNAL(playButtonClicked()), this, SLOT(play())); - connect(mPlayPage->mProfilesComboBox, - SIGNAL(currentIndexChanged(int)), - mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); - - connect(mDataFilesPage->mProfilesComboBox, - SIGNAL(currentIndexChanged(int)), - mPlayPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); + connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); + connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); } diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 780cd8beb3..643206ab6c 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -28,12 +28,6 @@ class MainDialog : public QMainWindow, private Ui::MainWindow public: MainDialog(); - - -// GameSettings &gameSettings, -// GraphicsSettings &GraphicsSettings, -// LauncherSettings &launcherSettings); - bool setup(); bool showFirstRunDialog(); @@ -58,9 +52,6 @@ private: void closeEvent(QCloseEvent *event); -// QListWidget *mIconWidget; -// QStackedWidget *mPagesWidget; - PlayPage *mPlayPage; GraphicsPage *mGraphicsPage; DataFilesPage *mDataFilesPage; diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index b082e2e2ce..27b7846ddd 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -4,45 +4,37 @@ PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { - QWidget *playWidget = new QWidget(this); - playWidget->setObjectName("PlayGroup"); - playWidget->setFixedSize(QSize(425, 375)); - - mPlayButton = new QPushButton(tr("Play"), playWidget); - mPlayButton->setObjectName("PlayButton"); - mPlayButton->setMinimumSize(QSize(200, 50)); - - QLabel *profileLabel = new QLabel(tr("Current Profile:"), playWidget); - profileLabel->setObjectName("ProfileLabel"); + setupUi(this); // Hacks to get the stylesheet look properly on different platforms QPlastiqueStyle *style = new QPlastiqueStyle; QFont font = QApplication::font(); font.setPointSize(12); // Fixes problem with overlapping items - mProfilesComboBox = new QComboBox(playWidget); - mProfilesComboBox->setObjectName("ProfilesComboBox"); - mProfilesComboBox->setStyle(style); - mProfilesComboBox->setFont(font); + profilesComboBox->setStyle(style); + profilesComboBox->setFont(font); - QGridLayout *playLayout = new QGridLayout(playWidget); - - QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - QSpacerItem *hSpacer2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - QSpacerItem *vSpacer1 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - QSpacerItem *vSpacer2 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - playLayout->addWidget(mPlayButton, 1, 1, 1, 1); - playLayout->addWidget(profileLabel, 2, 1, 1, 1); - playLayout->addWidget(mProfilesComboBox, 3, 1, 1, 1); - playLayout->addItem(hSpacer1, 2, 0, 1, 1); - playLayout->addItem(hSpacer2, 2, 2, 1, 1); - playLayout->addItem(vSpacer1, 0, 1, 1, 1); - playLayout->addItem(vSpacer2, 4, 1, 1, 1); - - QHBoxLayout *pageLayout = new QHBoxLayout(this); - - pageLayout->addWidget(playWidget); + connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int))); + connect(playButton, SIGNAL(clicked()), this, SLOT(slotPlayClicked())); } + +void PlayPage::setProfilesComboBoxModel(QAbstractItemModel *model) +{ + profilesComboBox->setModel(model); +} + +void PlayPage::setProfilesComboBoxIndex(int index) +{ + profilesComboBox->setCurrentIndex(index); +} + +void PlayPage::slotCurrentIndexChanged(int index) +{ + emit profileChanged(index); +} + +void PlayPage::slotPlayClicked() +{ + emit playButtonClicked(); +} diff --git a/apps/launcher/playpage.hpp b/apps/launcher/playpage.hpp index efec6f2b38..4306396bd2 100644 --- a/apps/launcher/playpage.hpp +++ b/apps/launcher/playpage.hpp @@ -3,19 +3,33 @@ #include +#include "ui_playpage.h" + class QComboBox; class QPushButton; +class QAbstractItemModel; -class PlayPage : public QWidget +class PlayPage : public QWidget, private Ui::PlayPage { Q_OBJECT public: PlayPage(QWidget *parent = 0); + void setProfilesComboBoxModel(QAbstractItemModel *model); + +signals: + void profileChanged(int index); + void playButtonClicked(); + +public slots: + void setProfilesComboBoxIndex(int index); + +private slots: + void slotCurrentIndexChanged(int index); + void slotPlayClicked(); + - QComboBox *mProfilesComboBox; - QPushButton *mPlayButton; }; -#endif \ No newline at end of file +#endif diff --git a/apps/launcher/ui/graphicspage.ui b/apps/launcher/ui/graphicspage.ui index 670b4f9c63..e04cd58559 100644 --- a/apps/launcher/ui/graphicspage.ui +++ b/apps/launcher/ui/graphicspage.ui @@ -1,7 +1,7 @@ - graphicsPage - + GraphicsPage + 0 diff --git a/apps/launcher/ui/playpage.ui b/apps/launcher/ui/playpage.ui index 86a763f648..ccd17f519c 100644 --- a/apps/launcher/ui/playpage.ui +++ b/apps/launcher/ui/playpage.ui @@ -1,107 +1,38 @@ - playPage - - - #playPage { + PlayPage + + + + + + #Scroll { background-image: url(":/images/playpage-background.png"); background-repeat: no-repeat; background-position: top; } - - - - 30 - - - 100 - - - 30 - - - - - - 200 - 85 - - - - 200 - 85 - + + QFrame::StyledPanel - - #playButton { - height: 50px; - margin-bottom: 30px; - - background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(255, 255, 255, 200), - stop:0.1 rgba(255, 255, 255, 15), - stop:0.49 rgba(255, 255, 255, 75), - stop:0.5 rgba(0, 0, 0, 0), - stop:0.9 rgba(0, 0, 0, 55), - stop:1 rgba(0, 0, 0, 100)); - - font-size: 26pt; - font-family: "EB Garamond", "EB Garamond 08"; - color: black; - - border-right: 1px solid rgba(0, 0, 0, 155); - border-left: 1px solid rgba(0, 0, 0, 55); - border-top: 1px solid rgba(0, 0, 0, 55); - border-bottom: 1px solid rgba(0, 0, 0, 155); - - border-radius: 5px; -} - -#playButton:hover { - border-bottom: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-top: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-right: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-left: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-width: 2px; - border-style: solid; -} - -#playButton:pressed { - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(0, 0, 0, 75), - stop:0.1 rgba(0, 0, 0, 15), - stop:0.2 rgba(255, 255, 255, 55) - stop:0.95 rgba(255, 255, 255, 55), - stop:1 rgba(255, 255, 255, 155)); - - border: 1px solid rgba(0, 0, 0, 55); -} + + QFrame::Plain - - Play - - - - - - - #profileLabel { - font-size: 18pt; - font-family: "EB Garamond", "EB Garamond 08"; -} - - - - Current Profile: - - - - - - - #profilesComboBox { + + + 30 + + + 100 + + + 30 + + + + + #profilesComboBox { padding: 1px 18px 1px 3px; background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 white, stop:0.2 rgba(0, 0, 0, 25), stop:1 white); @@ -155,22 +86,103 @@ border-radius: 5px; } - + + + + + + + #profileLabel { + font-size: 18pt; + font-family: "EB Garamond", "EB Garamond 08"; +} + + + + Current Profile: + + + + + + + + 200 + 85 + + + + + 200 + 85 + + + + #playButton { + height: 50px; + margin-bottom: 30px; + + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(255, 255, 255, 200), + stop:0.1 rgba(255, 255, 255, 15), + stop:0.49 rgba(255, 255, 255, 75), + stop:0.5 rgba(0, 0, 0, 0), + stop:0.9 rgba(0, 0, 0, 55), + stop:1 rgba(0, 0, 0, 100)); + + font-size: 26pt; + font-family: "EB Garamond", "EB Garamond 08"; + color: black; + + border-right: 1px solid rgba(0, 0, 0, 155); + border-left: 1px solid rgba(0, 0, 0, 55); + border-top: 1px solid rgba(0, 0, 0, 55); + border-bottom: 1px solid rgba(0, 0, 0, 155); + + border-radius: 5px; +} + +#playButton:hover { + border-bottom: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-top: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-right: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-left: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-width: 2px; + border-style: solid; +} + +#playButton:pressed { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(0, 0, 0, 75), + stop:0.1 rgba(0, 0, 0, 15), + stop:0.2 rgba(255, 255, 255, 55) + stop:0.95 rgba(255, 255, 255, 55), + stop:1 rgba(255, 255, 255, 155)); + + border: 1px solid rgba(0, 0, 0, 55); +} + + + Play + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + - - - - Qt::Vertical - - - - 20 - 40 - - - - From 8c0326a49c94583fc50eff481408c59654fdee6f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 18:30:28 -0800 Subject: [PATCH 0566/1483] Handle NiZBufferProperty --- components/nifogre/ogre_nif_loader.cpp | 33 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1d0d31961e..1ea911a77e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -553,7 +553,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop) + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -570,6 +571,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int alphaTest = 0; int vertMode = 2; //int lightMode = 1; + int depthFlags = 3; Ogre::String texName; bool vertexColour = (shape->data->colors.size() != 0); @@ -628,6 +630,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String //lightMode = vertprop->data.lightmode; } + if(zprop) + { + depthFlags = zprop->flags; + // Depth function??? + } + // Material if(matprop) { @@ -731,8 +739,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(((alphaFlags>>13)&1) ? - "off" : "on"))); + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::BooleanValue(!((alphaFlags>>13)&1)))); + + instance->setProperty("depth_check", sh::makeProperty(new sh::BooleanValue(depthFlags&1))); + instance->setProperty("depth_write", sh::makeProperty(new sh::BooleanValue((depthFlags>>1)&1))); + // depth_func??? sh::Factory::getInstance()._ensureMaterial(matname, "Default"); return matname; @@ -769,7 +780,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop) + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -969,7 +981,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, texprop, matprop, alphaprop, - vertprop); + vertprop, zprop); if(matname.length() > 0) sub->setMaterialName(matname); } @@ -978,7 +990,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiTexturingProperty *texprop=NULL, const Nif::NiMaterialProperty *matprop=NULL, const Nif::NiAlphaProperty *alphaprop=NULL, - const Nif::NiVertexColorProperty *vertprop=NULL) + const Nif::NiVertexColorProperty *vertprop=NULL, + const Nif::NiZBufferProperty *zprop=NULL) { // Scan the property list for material information const Nif::PropertyList &proplist = node->props; @@ -997,25 +1010,27 @@ class NIFMeshLoader : Ogre::ManualResourceLoader alphaprop = static_cast(pr); else if(pr->recType == Nif::RC_NiVertexColorProperty) vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop); + handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop); return true; } const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { - Nif::NodeList const &children = ninode->children; + const Nif::NodeList &children = ninode->children; for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop)) + if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop)) return true; } } From 8e35159ad4e5372d6bd0dcaad9542f33b8f3b753 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 19:06:28 -0800 Subject: [PATCH 0567/1483] Handle NiSpecularProperty --- components/nifogre/ogre_nif_loader.cpp | 33 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1ea911a77e..773a6b18db 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -554,7 +554,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop) + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -572,6 +573,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int vertMode = 2; //int lightMode = 1; int depthFlags = 3; + int specFlags = 1; Ogre::String texName; bool vertexColour = (shape->data->colors.size() != 0); @@ -636,6 +638,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // Depth function??? } + if(specprop) + { + specFlags = specprop->flags; + } + // Material if(matprop) { @@ -669,6 +676,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); boost::hash_combine(h, vertMode); + boost::hash_combine(h, specFlags); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -703,13 +711,16 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String else std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); + if(specFlags) + { + instance->setProperty("specular", sh::makeProperty( + new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); + } instance->setProperty("diffuseMap", sh::makeProperty(texName)); if (vertexColour) - instance->setProperty ("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Add transparency if NiAlphaProperty was present NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); @@ -781,7 +792,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop) + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -981,7 +993,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, texprop, matprop, alphaprop, - vertprop, zprop); + vertprop, zprop, specprop); if(matname.length() > 0) sub->setMaterialName(matname); } @@ -991,7 +1003,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiMaterialProperty *matprop=NULL, const Nif::NiAlphaProperty *alphaprop=NULL, const Nif::NiVertexColorProperty *vertprop=NULL, - const Nif::NiZBufferProperty *zprop=NULL) + const Nif::NiZBufferProperty *zprop=NULL, + const Nif::NiSpecularProperty *specprop=NULL) { // Scan the property list for material information const Nif::PropertyList &proplist = node->props; @@ -1012,13 +1025,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader vertprop = static_cast(pr); else if(pr->recType == Nif::RC_NiZBufferProperty) zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop); + handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop, specprop); return true; } @@ -1030,7 +1045,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop)) + if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop, specprop)) return true; } } From 7930aa82b2d90e96bc11dc9e20b99650561ebdba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 19:09:15 -0800 Subject: [PATCH 0568/1483] Add missing depthFlags to the hash --- components/nifogre/ogre_nif_loader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 773a6b18db..9537f550b5 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -676,6 +676,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); boost::hash_combine(h, vertMode); + boost::hash_combine(h, depthFlags); boost::hash_combine(h, specFlags); std::map::iterator itr = MaterialMap.find(h); From 21e2c287ebf60130db3669666d0557d8b34c4f7b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 19:30:23 -0800 Subject: [PATCH 0569/1483] Fix/workaround specular issues The glossiness should not be multiplied by 255, however the values set in many of Bloodmoon's meshes would look horrible otherwise. Now we can let the NiSpecularProperty specify when to enable specular (which is supposed to default to on, but due to the aforementioned meshes, we default to off). --- components/nifogre/ogre_nif_loader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9537f550b5..9652fd6055 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -573,7 +573,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int vertMode = 2; //int lightMode = 1; int depthFlags = 3; - int specFlags = 1; + // Default should be 1, but Bloodmoon's models are broken + int specFlags = 0; Ogre::String texName; bool vertexColour = (shape->data->colors.size() != 0); @@ -715,7 +716,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String if(specFlags) { instance->setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); + new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } instance->setProperty("diffuseMap", sh::makeProperty(texName)); From eb90bd71badf66f7368f2c936c3b844ab7b3076a Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 2 Mar 2013 21:34:55 -0600 Subject: [PATCH 0570/1483] Fixed triggering confirmation messages boxes when more than one view is open. --- apps/opencs/view/doc/viewmanager.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a5c7910c0f..63dd18291c 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -62,9 +62,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); } - // QMainWindow *mainWindow = new QMainWindow; - - View *view = new View (*this, document, countViews (document)+1); //, mainWindow); + View *view = new View (*this, document, countViews (document)+1); mViews.push_back (view); @@ -104,18 +102,21 @@ bool CSVDoc::ViewManager::closeRequest (View *view) CSMDoc::Document *document = view->getDocument(); - //notify user of saving in progress - if ( document->getState() & CSMDoc::State_Saving ) - continueWithClose = showSaveInProgressMessageBox (view); - else - //notify user of unsaved changes and process response - if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (view); + if (last) + { + //notify user of saving in progress + if ( (document->getState() & CSMDoc::State_Saving) ) + continueWithClose = showSaveInProgressMessageBox (view); + else + //notify user of unsaved changes and process response + if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (view); + } + + mViews.erase (iter); if (continueWithClose) { - mViews.erase (iter); - if (last) mDocumentManager.removeDocument (document); else From cf87708c1fc4a83aac6c668f3125020373371a5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 12:01:19 +0100 Subject: [PATCH 0571/1483] Magic effect icons for spells --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/hud.cpp | 23 ++- apps/openmw/mwgui/hud.hpp | 10 +- apps/openmw/mwgui/spellicons.cpp | 246 +++++++++++++++++++++++ apps/openmw/mwgui/spellicons.hpp | 47 +++++ apps/openmw/mwgui/spellwindow.cpp | 10 + apps/openmw/mwgui/spellwindow.hpp | 5 + apps/openmw/mwgui/tooltips.cpp | 12 +- apps/openmw/mwgui/tooltips.hpp | 4 + apps/openmw/mwgui/widgets.cpp | 12 +- apps/openmw/mwgui/windowmanagerimp.cpp | 3 + apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwmechanics/activespells.cpp | 5 + apps/openmw/mwmechanics/activespells.hpp | 2 + files/mygui/openmw_hud.layout | 5 +- files/mygui/openmw_hud_box.skin.xml | 4 + files/mygui/openmw_spell_window.layout | 4 +- 17 files changed, 360 insertions(+), 35 deletions(-) create mode 100644 apps/openmw/mwgui/spellicons.cpp create mode 100644 apps/openmw/mwgui/spellicons.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 7cfeb84c5e..e09dfb1083 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -30,7 +30,7 @@ add_openmw_dir (mwgui formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor + enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a2c3a318ba..2eb96249cc 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -19,6 +19,7 @@ #include "inventorywindow.hpp" #include "container.hpp" #include "console.hpp" +#include "spellicons.hpp" using namespace MWGui; @@ -32,7 +33,6 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) , mWeapStatus(NULL) , mSpellStatus(NULL) , mEffectBox(NULL) - , mEffect1(NULL) , mMinimap(NULL) , mCompass(NULL) , mCrosshair(NULL) @@ -86,9 +86,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); getWidget(mEffectBox, "EffectBox"); - getWidget(mEffect1, "Effect1"); mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); - mEffectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); getWidget(mMinimapBox, "MiniMapBox"); mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); @@ -107,13 +105,18 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(mTriangleCounter, "TriangleCounter"); getWidget(mBatchCounter, "BatchCounter"); - setEffect("icons\\s\\tx_s_chameleon.dds"); - LocalMapBase::init(mMinimap, mCompass, this); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); + + mSpellIcons = new SpellIcons(); +} + +HUD::~HUD() +{ + delete mSpellIcons; } void HUD::setFpsLevel(int level) @@ -156,11 +159,6 @@ void HUD::setBatchCount(unsigned int count) mBatchCounter->setCaption(boost::lexical_cast(count)); } -void HUD::setEffect(const char *img) -{ - mEffect1->setImageTexture(img); -} - void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { static const char *ids[] = @@ -542,3 +540,8 @@ void HUD::updatePositions() mMapVisible = mMinimapBox->getVisible (); mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); } + +void HUD::update() +{ + mSpellIcons->updateWidgets(mEffectBox, true); +} diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 013ad59f05..39d6eadca3 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -8,12 +8,13 @@ namespace MWGui { class DragAndDrop; + class SpellIcons; class HUD : public OEngine::GUI::Layout, public LocalMapBase { public: HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); - void setEffect(const char *img); + virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); void setTriangleCount(unsigned int count); @@ -43,6 +44,10 @@ namespace MWGui bool getWorldMouseOver() { return mWorldMouseOver; } + MyGUI::Widget* getEffectBox() { return mEffectBox; } + + void update(); + private: MyGUI::ProgressPtr mHealth, mMagicka, mStamina; MyGUI::Widget* mHealthFrame; @@ -51,7 +56,6 @@ namespace MWGui MyGUI::ProgressPtr mWeapStatus, mSpellStatus; MyGUI::Widget *mEffectBox, *mMinimapBox; MyGUI::Button* mMinimapButton; - MyGUI::ImageBox* mEffect1; MyGUI::ScrollView* mMinimap; MyGUI::ImageBox* mCompass; MyGUI::ImageBox* mCrosshair; @@ -85,6 +89,8 @@ namespace MWGui bool mWorldMouseOver; + SpellIcons* mSpellIcons; + void onWorldClicked(MyGUI::Widget* _sender); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp new file mode 100644 index 0000000000..19b2a87ec4 --- /dev/null +++ b/apps/openmw/mwgui/spellicons.cpp @@ -0,0 +1,246 @@ +#include "spellicons.hpp" + +#include +#include +#include + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/activespells.hpp" +#include "../mwmechanics/creaturestats.hpp" + +#include "tooltips.hpp" + + +namespace MWGui +{ + + void SpellIcons::updateWidgets(MyGUI::Widget *parent, bool adjustSize) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + + std::map > effects; + + // add permanent spells + const MWMechanics::Spells& spells = stats.getSpells(); + for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); + + // these are the spell types that are permanently in effect + if (!(spell->mData.mType == ESM::Spell::ST_Ability) + && !(spell->mData.mType == ESM::Spell::ST_Disease) + && !(spell->mData.mType == ESM::Spell::ST_Curse) + && !(spell->mData.mType == ESM::Spell::ST_Blight)) + continue; + ESM::EffectList list = spell->mEffects; + for (std::vector::const_iterator effectIt = list.mList.begin(); + effectIt != list.mList.end(); ++effectIt) + { + const ESM::MagicEffect* magicEffect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(effectIt->mEffectID); + MagicEffectInfo effectInfo; + effectInfo.mSource = getSpellDisplayName (it->first); + effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID); + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + effectInfo.mKey.mArg = effectIt->mSkill; + else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + effectInfo.mKey.mArg = effectIt->mAttribute; + // just using the min magnitude here, permanent spells with a random magnitude just wouldn't make any sense + effectInfo.mMagnitude = effectIt->mMagnMin; + effectInfo.mPermanent = true; + + effects[effectIt->mEffectID].push_back (effectInfo); + } + } + + // add lasting effect spells/potions etc + const MWMechanics::ActiveSpells::TContainer& activeSpells = stats.getActiveSpells().getActiveSpells(); + for (MWMechanics::ActiveSpells::TContainer::const_iterator it = activeSpells.begin(); + it != activeSpells.end(); ++it) + { + ESM::EffectList list = getSpellEffectList(it->first); + + float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + + for (std::vector::const_iterator effectIt = list.mList.begin(); + effectIt != list.mList.end(); ++effectIt) + { + const ESM::MagicEffect* magicEffect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(effectIt->mEffectID); + + MagicEffectInfo effectInfo; + effectInfo.mSource = getSpellDisplayName (it->first); + effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID); + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + effectInfo.mKey.mArg = effectIt->mSkill; + else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + effectInfo.mKey.mArg = effectIt->mAttribute; + effectInfo.mMagnitude = effectIt->mMagnMin + (effectIt->mMagnMax-effectIt->mMagnMin) * it->second.second; + effectInfo.mRemainingTime = effectIt->mDuration + + (it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + + effects[effectIt->mEffectID].push_back (effectInfo); + } + } + + parent->setVisible(effects.size() != 0); + + int w=2; + if (adjustSize) + { + int s = effects.size() * 16+4; + int diff = parent->getWidth() - s; + parent->setSize(s, parent->getHeight()); + parent->setPosition(parent->getLeft()+diff, parent->getTop()); + } + + + for (std::map >::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + MyGUI::ImageBox* image; + if (mWidgetMap.find(it->first) == mWidgetMap.end()) + image = parent->createWidget + ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); + else + image = mWidgetMap[it->first]; + mWidgetMap[it->first] = image; + image->setPosition(w,2); + image->setVisible(true); + + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(it->first); + + std::string icon = effect->mIcon; + icon[icon.size()-3] = 'd'; + icon[icon.size()-2] = 'd'; + icon[icon.size()-1] = 's'; + icon = "icons\\" + icon; + + image->setImageTexture(icon); + w += 16; + + float remainingDuration = 0; + + std::string sourcesDescription; + + const float fadeTime = 5.f; + + for (std::vector::const_iterator effectIt = it->second.begin(); + effectIt != it->second.end(); ++effectIt) + { + if (effectIt != it->second.begin()) + sourcesDescription += "\n"; + + // if at least one of the effect sources is permanent, the effect will never wear off + if (effectIt->mPermanent) + remainingDuration = fadeTime; + else + remainingDuration = std::max(remainingDuration, effectIt->mRemainingTime); + + sourcesDescription += effectIt->mSource; + + if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) + sourcesDescription += " (" + + MWBase::Environment::get().getWindowManager()->getGameSettingString( + ESM::Skill::sSkillNameIds[effectIt->mKey.mArg], "") + ")"; + if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + sourcesDescription += " (" + + MWBase::Environment::get().getWindowManager()->getGameSettingString( + ESM::Attribute::sGmstAttributeIds[effectIt->mKey.mArg], "") + ")"; + + if (!(effect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) + { + std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); + std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + + sourcesDescription += ": " + boost::lexical_cast(effectIt->mMagnitude); + sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? pts : pt); + } + } + + std::string name = ESM::MagicEffect::effectIdToString (it->first); + + ToolTipInfo tooltipInfo; + tooltipInfo.caption = "#{" + name + "}"; + tooltipInfo.icon = effect->mIcon; + tooltipInfo.text = sourcesDescription; + tooltipInfo.imageSize = 16; + tooltipInfo.wordWrap = false; + + image->setUserData(tooltipInfo); + image->setUserString("ToolTipType", "ToolTipInfo"); + + // Fade out during the last 5 seconds + image->setAlpha(std::min(remainingDuration/fadeTime, 1.f)); + } + + // hide inactive effects + for (std::map::iterator it = mWidgetMap.begin(); it != mWidgetMap.end(); ++it) + { + if (effects.find(it->first) == effects.end()) + it->second->setVisible(false); + } + + } + + + std::string SpellIcons::getSpellDisplayName (const std::string& id) + { + if (const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return spell->mName; + + if (const ESM::Potion *potion = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return potion->mName; + + if (const ESM::Ingredient *ingredient = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return ingredient->mName; + + throw std::runtime_error ("ID " + id + " has no display name"); + } + + ESM::EffectList SpellIcons::getSpellEffectList (const std::string& id) + { + if (const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return spell->mEffects; + + if (const ESM::Potion *potion = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return potion->mEffects; + + if (const ESM::Ingredient *ingredient = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + { + const ESM::MagicEffect *magicEffect = + MWBase::Environment::get().getWorld()->getStore().get().find ( + ingredient->mData.mEffectID[0]); + + ESM::ENAMstruct effect; + effect.mEffectID = ingredient->mData.mEffectID[0]; + effect.mSkill = ingredient->mData.mSkills[0]; + effect.mAttribute = ingredient->mData.mAttributes[0]; + effect.mRange = 0; + effect.mArea = 0; + effect.mDuration = magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration ? 0 : 1; + effect.mMagnMin = 1; + effect.mMagnMax = 1; + ESM::EffectList result; + result.mList.push_back (effect); + return result; + } + throw std::runtime_error("ID " + id + " does not have effects"); + } + +} diff --git a/apps/openmw/mwgui/spellicons.hpp b/apps/openmw/mwgui/spellicons.hpp new file mode 100644 index 0000000000..af600e3474 --- /dev/null +++ b/apps/openmw/mwgui/spellicons.hpp @@ -0,0 +1,47 @@ +#ifndef MWGUI_SPELLICONS_H +#define MWGUI_SPELLICONS_H + +#include + +#include "../mwmechanics/magiceffects.hpp" + +namespace MyGUI +{ + class Widget; + class ImageBox; +} +namespace ESM +{ + struct ENAMstruct; + struct EffectList; +} + +namespace MWGui +{ + + // information about a single magic effect source as required for display in the tooltip + struct MagicEffectInfo + { + MagicEffectInfo() : mPermanent(false) {} + std::string mSource; // display name for effect source (e.g. potion name) + MWMechanics::EffectKey mKey; + int mMagnitude; + float mRemainingTime; + bool mPermanent; // the effect is permanent + }; + + class SpellIcons + { + public: + void updateWidgets(MyGUI::Widget* parent, bool adjustSize); + + private: + std::string getSpellDisplayName (const std::string& id); + ESM::EffectList getSpellEffectList (const std::string& id); + + std::map mWidgetMap; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 47e1d739a7..50691d5540 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" +#include "spellicons.hpp" #include "inventorywindow.hpp" #include "confirmationdialog.hpp" @@ -51,6 +52,8 @@ namespace MWGui , mHeight(0) , mWidth(0) { + mSpellIcons = new SpellIcons(); + getWidget(mSpellView, "SpellView"); getWidget(mEffectBox, "EffectsBox"); @@ -61,6 +64,11 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize); } + SpellWindow::~SpellWindow() + { + delete mSpellIcons; + } + void SpellWindow::onPinToggled() { mWindowManager.setSpellVisibility(!mPinned); @@ -73,6 +81,8 @@ namespace MWGui void SpellWindow::updateSpells() { + mSpellIcons->updateWidgets(mEffectBox, false); + const int spellHeight = 18; mHeight = 0; diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index caa67fd740..1963d43463 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -5,10 +5,13 @@ namespace MWGui { + class SpellIcons; + class SpellWindow : public WindowPinnableBase { public: SpellWindow(MWBase::WindowManager& parWindowManager); + virtual ~SpellWindow(); void updateSpells(); @@ -33,6 +36,8 @@ namespace MWGui virtual void onPinToggled(); virtual void open(); + + SpellIcons* mSpellIcons; }; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c7acf568d1..b42f9ac255 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -127,9 +127,7 @@ void ToolTips::onFrame(float frameDuration) Widget* focus = InputManager::getInstance().getMouseFocusWidget(); if (focus == 0) - { return; - } IntSize tooltipSize; @@ -168,6 +166,10 @@ void ToolTips::onFrame(float frameDuration) mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(false); } + else if (type == "ToolTipInfo") + { + tooltipSize = createToolTip(*focus->getUserData()); + } else if (type == "AvatarItemSelection") { MyGUI::IntCoord avatarPos = mWindowManager->getInventoryWindow ()->getAvatarScreenCoord (); @@ -363,7 +365,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) std::string caption = info.caption; std::string image = info.icon; - int imageSize = (image != "") ? 32 : 0; + int imageSize = (image != "") ? info.imageSize : 0; std::string text = info.text; // remove the first newline (easier this way) @@ -403,7 +405,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption"); captionWidget->setProperty("Static", "true"); - captionWidget->setCaption(caption); + captionWidget->setCaptionWithReplacing(caption); IntSize captionSize = captionWidget->getTextSize(); int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); @@ -411,7 +413,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), Align::Stretch, "ToolTipText"); textWidget->setProperty("Static", "true"); textWidget->setProperty("MultiLine", "true"); - textWidget->setProperty("WordWrap", "true"); + textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); textWidget->setCaptionWithReplacing(text); textWidget->setTextAlign(Align::HCenter | Align::Top); IntSize textSize = textWidget->getTextSize(); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 4048d0d5a5..ba94915cc7 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -15,11 +15,14 @@ namespace MWGui public: ToolTipInfo() : isPotion(false) + , imageSize(32) + , wordWrap(true) {} std::string caption; std::string text; std::string icon; + int imageSize; // enchantment (for cloth, armor, weapons) std::string enchant; @@ -28,6 +31,7 @@ namespace MWGui Widgets::SpellEffectList effects; bool isPotion; // potions do not show target in the tooltip + bool wordWrap; }; class ToolTips : public OEngine::GUI::Layout diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index f932c1f034..ade681963f 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -421,17 +421,7 @@ void MWSpellEffect::updateWidgets() } if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) { - static const char *attributes[8] = { - "sAttributeStrength", - "sAttributeIntelligence", - "sAttributeWillpower", - "sAttributeAgility", - "sAttributeSpeed", - "sAttributeEndurance", - "sAttributePersonality", - "sAttributeLuck" - }; - spellLine += " " + mWindowManager->getGameSettingString(attributes[mEffectParams.mAttribute], ""); + spellLine += " " + mWindowManager->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); } if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1138f62faa..0110171e67 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -54,6 +54,7 @@ #include "imagebutton.hpp" #include "exposedwindow.hpp" #include "cursor.hpp" +#include "spellicons.hpp" using namespace MWGui; @@ -270,6 +271,8 @@ void WindowManager::update() mHud->setTriangleCount(mTriangleCount); mHud->setBatchCount(mBatchCount); + mHud->update(); + mCursor->update(); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e2d64a855d..4e8f121601 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -73,6 +73,7 @@ namespace MWGui class EnchantingDialog; class TrainingWindow; class Cursor; + class SpellIcons; class WindowManager : public MWBase::WindowManager { diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index ee1e9da362..933c5094d9 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -274,4 +274,9 @@ namespace MWMechanics } return false; } + + const ActiveSpells::TContainer& ActiveSpells::getActiveSpells() const + { + return mSpells; + } } diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 6b832f4cdc..05aa2bbdde 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -63,6 +63,8 @@ namespace MWMechanics const MagicEffects& getMagicEffects() const; + const TContainer& getActiveSpells() const; + TIterator begin() const; TIterator end() const; diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index e4c6f0765e..382bc6dc98 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -61,10 +61,7 @@ - - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 23480e8d35..f847ca51ab 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -16,6 +16,10 @@
+ + + + diff --git a/files/mygui/openmw_spell_window.layout b/files/mygui/openmw_spell_window.layout index 6c6629605b..18a5af352b 100644 --- a/files/mygui/openmw_spell_window.layout +++ b/files/mygui/openmw_spell_window.layout @@ -4,8 +4,8 @@ - - + + From 8e05c4159d309259cd31fd30181e1593d0e02ffb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 12:17:37 +0100 Subject: [PATCH 0572/1483] Magic effect icons for permanent enchantments --- apps/openmw/mwgui/spellicons.cpp | 40 ++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 19b2a87ec4..dcbbed49c7 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -12,6 +12,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwmechanics/activespells.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -29,6 +30,41 @@ namespace MWGui std::map > effects; + // add permanent item enchantments + MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = store.getSlot(slot); + if (it == store.end()) + continue; + std::string enchantment = MWWorld::Class::get(*it).getEnchantment(*it); + if (enchantment.empty()) + continue; + const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().get().find(enchantment); + if (enchant->mData.mType != ESM::Enchantment::ConstantEffect) + continue; + + const ESM::EffectList& list = enchant->mEffects; + for (std::vector::const_iterator effectIt = list.mList.begin(); + effectIt != list.mList.end(); ++effectIt) + { + const ESM::MagicEffect* magicEffect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(effectIt->mEffectID); + + MagicEffectInfo effectInfo; + effectInfo.mSource = MWWorld::Class::get(*it).getName(*it); + effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID); + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + effectInfo.mKey.mArg = effectIt->mSkill; + else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + effectInfo.mKey.mArg = effectIt->mAttribute; + // just using the min magnitude here, permanent enchantments with a random magnitude just wouldn't make any sense + effectInfo.mMagnitude = effectIt->mMagnMin; + effectInfo.mPermanent = true; + effects[effectIt->mEffectID].push_back (effectInfo); + } + } + // add permanent spells const MWMechanics::Spells& spells = stats.getSpells(); for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) @@ -41,7 +77,7 @@ namespace MWGui && !(spell->mData.mType == ESM::Spell::ST_Curse) && !(spell->mData.mType == ESM::Spell::ST_Blight)) continue; - ESM::EffectList list = spell->mEffects; + const ESM::EffectList& list = spell->mEffects; for (std::vector::const_iterator effectIt = list.mList.begin(); effectIt != list.mList.end(); ++effectIt) { @@ -67,7 +103,7 @@ namespace MWGui for (MWMechanics::ActiveSpells::TContainer::const_iterator it = activeSpells.begin(); it != activeSpells.end(); ++it) { - ESM::EffectList list = getSpellEffectList(it->first); + const ESM::EffectList& list = getSpellEffectList(it->first); float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); From 6f05c4229f9183c04687fba5cc172bddb6e475d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 12:41:37 +0100 Subject: [PATCH 0573/1483] Implemented potion & ingredient effect stacking --- apps/openmw/mwmechanics/activespells.cpp | 32 +++++++++++++----------- apps/openmw/mwmechanics/activespells.hpp | 5 ++-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 933c5094d9..9aca6b7b79 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -62,7 +62,7 @@ namespace MWMechanics for (TIterator iter (begin()); iter!=end(); ++iter) { - std::pair effects = getEffectList (iter->first); + std::pair > effects = getEffectList (iter->first); const MWWorld::TimeStamp& start = iter->second.first; float magnitude = iter->second.second; @@ -74,7 +74,7 @@ namespace MWMechanics { int duration = iter->mDuration; - if (effects.second) + if (effects.second.first) duration *= magnitude; MWWorld::TimeStamp end = start; @@ -85,7 +85,7 @@ namespace MWMechanics { EffectParam param; - if (effects.second) + if (effects.second.first) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( @@ -113,15 +113,15 @@ namespace MWMechanics } } - std::pair ActiveSpells::getEffectList (const std::string& id) const + std::pair > ActiveSpells::getEffectList (const std::string& id) const { if (const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().search (id)) - return std::make_pair (spell->mEffects, false); + return std::make_pair (spell->mEffects, std::make_pair(false, false)); if (const ESM::Potion *potion = MWBase::Environment::get().getWorld()->getStore().get().search (id)) - return std::make_pair (potion->mEffects, false); + return std::make_pair (potion->mEffects, std::make_pair(false, true)); if (const ESM::Ingredient *ingredient = MWBase::Environment::get().getWorld()->getStore().get().search (id)) @@ -140,11 +140,12 @@ namespace MWMechanics effect.mMagnMin = 1; effect.mMagnMax = 1; - std::pair result; - + std::pair > result; + result.second.second = true; + result.second.first = true; + result.first.mList.push_back (effect); - result.second = true; - + return result; } @@ -157,7 +158,8 @@ namespace MWMechanics bool ActiveSpells::addSpell (const std::string& id, const MWWorld::Ptr& actor) { - std::pair effects = getEffectList (id); + std::pair > effects = getEffectList (id); + bool stacks = effects.second.second; bool found = false; @@ -178,7 +180,7 @@ namespace MWMechanics float random = static_cast (std::rand()) / RAND_MAX; - if (effects.second) + if (effects.second.first) { // ingredient -> special treatment required. const CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); @@ -194,7 +196,7 @@ namespace MWMechanics random *= 0.25 * x; } - if (iter==mSpells.end()) + if (iter==mSpells.end() || stacks) mSpells.insert (std::make_pair (id, std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random))); else @@ -236,7 +238,7 @@ namespace MWMechanics double ActiveSpells::timeToExpire (const TIterator& iterator) const { - std::pair effects = getEffectList (iterator->first); + std::pair > effects = getEffectList (iterator->first); int duration = 0; @@ -247,7 +249,7 @@ namespace MWMechanics duration = iter->mDuration; } - if (effects.second) + if (effects.second.first) duration *= iterator->second.second; double scaledDuration = duration * diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 05aa2bbdde..8c859b2cb3 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -30,7 +30,7 @@ namespace MWMechanics { public: - typedef std::map > TContainer; + typedef std::multimap > TContainer; typedef TContainer::const_iterator TIterator; private: @@ -44,7 +44,8 @@ namespace MWMechanics void rebuildEffects() const; - std::pair getEffectList (const std::string& id) const; + std::pair > getEffectList (const std::string& id) const; + ///< @return (EffectList, (isIngredient, stacks)) public: From 6037c44ea6850595bace11f5f0bde64f5ae8f31e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 12:41:57 +0100 Subject: [PATCH 0574/1483] Fix ingredient effect display --- apps/openmw/mwgui/spellicons.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index dcbbed49c7..16e02ebba1 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -124,6 +124,17 @@ namespace MWGui effectInfo.mRemainingTime = effectIt->mDuration + (it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + // ingredients need special casing for their magnitude / duration + /// \todo duplicated from ActiveSpells, helper function? + if (MWBase::Environment::get().getWorld()->getStore().get().search (it->first)) + { + effectInfo.mRemainingTime = effectIt->mDuration * it->second.second + + (it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + + effectInfo.mMagnitude = static_cast (0.05*it->second.second / (0.1 * magicEffect->mData.mBaseCost)); + } + + effects[effectIt->mEffectID].push_back (effectInfo); } } From 9a84f6744f561a4e8dd1e86d652602dae19ca330 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 13:11:02 +0100 Subject: [PATCH 0575/1483] Fix headers including whole MyGUI.h, forward declare where appropriate, and fix some deprecated types (WidgetPtr) --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/birth.cpp | 12 +++--- apps/openmw/mwgui/birth.hpp | 4 +- apps/openmw/mwgui/class.cpp | 56 +++++++++++++------------- apps/openmw/mwgui/class.hpp | 18 ++++----- apps/openmw/mwgui/console.cpp | 4 +- apps/openmw/mwgui/console.hpp | 8 ++-- apps/openmw/mwgui/cursor.cpp | 4 +- apps/openmw/mwgui/dialogue.cpp | 6 +-- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/exposedwindow.cpp | 4 +- apps/openmw/mwgui/exposedwindow.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 4 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/imagebutton.hpp | 2 +- apps/openmw/mwgui/journalwindow.hpp | 4 +- apps/openmw/mwgui/list.cpp | 5 ++- apps/openmw/mwgui/list.hpp | 7 +++- apps/openmw/mwgui/messagebox.cpp | 10 ++--- apps/openmw/mwgui/messagebox.hpp | 16 +++++--- apps/openmw/mwgui/race.cpp | 16 ++++---- apps/openmw/mwgui/race.hpp | 8 ++-- apps/openmw/mwgui/review.cpp | 6 +-- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/stats_window.cpp | 4 +- apps/openmw/mwgui/stats_window.hpp | 4 +- apps/openmw/mwgui/text_input.cpp | 4 +- apps/openmw/mwgui/text_input.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 4 +- apps/openmw/mwgui/widgets.cpp | 47 +++++++++++---------- apps/openmw/mwgui/widgets.hpp | 22 ++++++---- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- libs/openengine/gui/manager.cpp | 9 +++-- libs/openengine/gui/manager.hpp | 2 + 34 files changed, 166 insertions(+), 138 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index db1a81c2c2..fce6126001 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -237,7 +237,7 @@ namespace MWGui Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list); effectsWidget->setEffectList(_list); - std::vector effectItems; + std::vector effectItems; effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0); effectsWidget->setCoord(coord); } diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 53e5c022d2..4b07dd698c 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -40,11 +40,11 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); @@ -55,7 +55,7 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) void BirthDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) @@ -82,7 +82,7 @@ void BirthDialog::setBirthId(const std::string &birthId) if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) { mBirthList->setIndexSelected(i); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); break; } @@ -110,7 +110,7 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); const std::string *birthId = mBirthList->getItemDataAt(_index); @@ -159,7 +159,7 @@ void BirthDialog::updateBirths() void BirthDialog::updateSpells() { - for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) + for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index ad1c0b40f5..d3f82dace4 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -46,9 +46,9 @@ namespace MWGui void updateSpells(); MyGUI::ListBox* mBirthList; - MyGUI::WidgetPtr mSpellArea; + MyGUI::Widget* mSpellArea; MyGUI::ImageBox* mBirthImage; - std::vector mSpellItems; + std::vector mSpellItems; std::string mCurrentBirthId; }; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index f3bac898b2..a2f09096a1 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -31,11 +31,11 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW getWidget(mClassImage, "ClassImage"); getWidget(mClassName, "ClassName"); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); @@ -97,11 +97,11 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) getWidget(mClassImage, "ClassImage"); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); @@ -111,7 +111,7 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) void PickClassDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) @@ -138,7 +138,7 @@ void PickClassDialog::setClassId(const std::string &classId) if (boost::iequals(*mClassList->getItemDataAt(i), classId)) { mClassList->setIndexSelected(i); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); break; } @@ -166,7 +166,7 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); const std::string *classId = mClassList->getItemDataAt(_index); @@ -256,7 +256,7 @@ void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) widget->setSize(size); } -void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) +void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) { size_t count = widget->getChildCount(); int pos = 0; @@ -264,7 +264,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) int width = 0; for (unsigned i = 0; i < count; ++i) { - MyGUI::WidgetPtr child = widget->getChildAt(i); + MyGUI::Widget* child = widget->getChildAt(i); if (!child->getVisible()) continue; @@ -302,7 +302,7 @@ std::string InfoBoxDialog::getText() const void InfoBoxDialog::setButtons(ButtonList &buttons) { - for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) + for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } @@ -310,7 +310,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons) mCurrentButton = -1; // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget - MyGUI::ButtonPtr button; + MyGUI::Button* button; MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); ButtonList::const_iterator end = buttons.end(); for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) @@ -342,11 +342,11 @@ int InfoBoxDialog::getChosenButton() const return mCurrentButton; } -void InfoBoxDialog::onButtonClicked(MyGUI::WidgetPtr _sender) +void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) { - std::vector::const_iterator end = mButtons.end(); + std::vector::const_iterator end = mButtons.end(); int i = 0; - for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) + for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) { if (*it == _sender) { @@ -376,10 +376,10 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) : WindowModal("openmw_chargen_create_class.layout", parWindowManager) - , mSpecDialog(nullptr) - , mAttribDialog(nullptr) - , mSkillDialog(nullptr) - , mDescDialog(nullptr) + , mSpecDialog(NULL) + , mAttribDialog(NULL) + , mSkillDialog(NULL) + , mDescDialog(NULL) { // Centre dialog center(); @@ -420,15 +420,15 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); - MyGUI::ButtonPtr descriptionButton; + MyGUI::Button* descriptionButton; getWidget(descriptionButton, "DescriptionButton"); descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); @@ -518,7 +518,7 @@ std::vector CreateClassDialog::getMinorSkills() const void CreateClassDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) @@ -544,7 +544,7 @@ void CreateClassDialog::onDialogCancel() mDescDialog = 0; } -void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) +void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) { delete mSpecDialog; mSpecDialog = new SelectSpecializationDialog(mWindowManager); @@ -694,7 +694,7 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); - MyGUI::ButtonPtr cancelButton; + MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); @@ -706,7 +706,7 @@ SelectSpecializationDialog::~SelectSpecializationDialog() // widget controls -void SelectSpecializationDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) +void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender) { if (_sender == mSpecialization0) mSpecializationId = ESM::Class::Combat; @@ -747,7 +747,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); } - MyGUI::ButtonPtr cancelButton; + MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); @@ -840,7 +840,7 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) } } - MyGUI::ButtonPtr cancelButton; + MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); @@ -873,7 +873,7 @@ DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) getWidget(mTextEdit, "TextEdit"); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", "")); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 2662d94ccf..8c60331d87 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_CLASS_H #define MWGUI_CLASS_H -#include + #include "widgets.hpp" #include "window_base.hpp" @@ -35,17 +35,17 @@ namespace MWGui EventHandle_Int eventButtonSelected; protected: - void onButtonClicked(MyGUI::WidgetPtr _sender); + void onButtonClicked(MyGUI::Widget* _sender); private: void fitToText(MyGUI::TextBox* widget); - void layoutVertically(MyGUI::WidgetPtr widget, int margin); + void layoutVertically(MyGUI::Widget* widget, int margin); int mCurrentButton; - MyGUI::WidgetPtr mTextBox; + MyGUI::Widget* mTextBox; MyGUI::TextBox* mText; - MyGUI::WidgetPtr mButtonBar; - std::vector mButtons; + MyGUI::Widget* mButtonBar; + std::vector mButtons; }; // Lets the player choose between 3 ways of creating a class @@ -235,7 +235,7 @@ namespace MWGui void onOkClicked(MyGUI::Widget* _sender); private: - MyGUI::EditPtr mTextEdit; + MyGUI::EditBox* mTextEdit; }; class CreateClassDialog : public WindowModal @@ -265,7 +265,7 @@ namespace MWGui void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); - void onSpecializationClicked(MyGUI::WidgetPtr _sender); + void onSpecializationClicked(MyGUI::Widget* _sender); void onSpecializationSelected(); void onAttributeClicked(Widgets::MWAttributePtr _sender); void onAttributeSelected(); @@ -280,7 +280,7 @@ namespace MWGui void update(); private: - MyGUI::EditPtr mEditName; + MyGUI::EditBox* mEditName; MyGUI::TextBox* mSpecializationName; Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1; Widgets::MWSkillPtr mMajorSkill[5]; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index b2281d87e6..1aebe57da2 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -216,7 +216,7 @@ namespace MWGui } } - void Console::keyPress(MyGUI::WidgetPtr _sender, + void Console::keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char) { @@ -266,7 +266,7 @@ namespace MWGui } } - void Console::acceptCommand(MyGUI::EditPtr _sender) + void Console::acceptCommand(MyGUI::EditBox* _sender) { const std::string &cm = command->getCaption(); if(cm.empty()) return; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 1893b01486..b1d961ed20 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -55,8 +55,8 @@ namespace MWGui public: - MyGUI::EditPtr command; - MyGUI::EditPtr history; + MyGUI::EditBox* command; + MyGUI::EditBox* history; typedef std::list StringList; @@ -95,11 +95,11 @@ namespace MWGui private: - void keyPress(MyGUI::WidgetPtr _sender, + void keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char); - void acceptCommand(MyGUI::EditPtr _sender); + void acceptCommand(MyGUI::EditBox* _sender); std::string complete( std::string input, std::vector &matches ); }; diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 15f61d5b66..399695ae3f 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -14,7 +14,7 @@ namespace MWGui ResourceImageSetPointerFix::ResourceImageSetPointerFix() : - mImageSet(nullptr) + mImageSet(NULL) { } @@ -50,7 +50,7 @@ namespace MWGui void ResourceImageSetPointerFix::setImage(MyGUI::ImageBox* _image) { - if (mImageSet != nullptr) + if (mImageSet != NULL) _image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0)); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index c7918ceb78..859e3008cc 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -151,7 +151,7 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) getWidget(mTopicsList, "TopicsList"); mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - MyGUI::ButtonPtr byeButton; + MyGUI::Button* byeButton; getWidget(byeButton, "ByeButton"); byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); @@ -164,7 +164,7 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) { MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); - if(t == nullptr) + if(t == NULL) return; const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); @@ -381,7 +381,7 @@ std::string DialogueWindow::parseText(const std::string& text) std::vector hypertext = MWDialogue::ParseHyperText(text); size_t historySize = 0; - if(mHistory->getClient()->getSubWidgetText() != nullptr) + if(mHistory->getClient()->getSubWidgetText() != NULL) { historySize = mHistory->getOnlyText().size(); } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5c11c311ac..e39cecc3cf 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -113,7 +113,7 @@ namespace MWGui DialogueHistory* mHistory; Widgets::MWList* mTopicsList; MyGUI::ProgressPtr mDispositionBar; - MyGUI::EditPtr mDispositionText; + MyGUI::EditBox* mDispositionText; PersuasionDialog mPersuasionDialog; diff --git a/apps/openmw/mwgui/exposedwindow.cpp b/apps/openmw/mwgui/exposedwindow.cpp index fa37568d7b..150a8c893a 100644 --- a/apps/openmw/mwgui/exposedwindow.cpp +++ b/apps/openmw/mwgui/exposedwindow.cpp @@ -1,7 +1,5 @@ #include "exposedwindow.hpp" -#include "MyGUI_Window.h" - namespace MWGui { MyGUI::VectorWidgetPtr ExposedWindow::getSkinWidgetsByName (const std::string &name) @@ -16,7 +14,7 @@ namespace MWGui if (widgets.empty()) { MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' not found in skin of layout '" << getName() << "'"); - return nullptr; + return NULL; } else { diff --git a/apps/openmw/mwgui/exposedwindow.hpp b/apps/openmw/mwgui/exposedwindow.hpp index 906d0b4065..7df2fcb358 100644 --- a/apps/openmw/mwgui/exposedwindow.hpp +++ b/apps/openmw/mwgui/exposedwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_EXPOSEDWINDOW_H #define MWGUI_EXPOSEDWINDOW_H -#include "MyGUI_Window.h" +#include namespace MWGui { diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a2c3a318ba..7cb0f39240 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -2,7 +2,9 @@ #include -#include +#include +#include +#include #include diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 013ad59f05..51dcffb090 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -60,7 +60,7 @@ namespace MWGui MyGUI::Widget* mDummy; - MyGUI::WidgetPtr mFpsBox; + MyGUI::Widget* mFpsBox; MyGUI::TextBox* mFpsCounter; MyGUI::TextBox* mTriangleCounter; MyGUI::TextBox* mBatchCounter; diff --git a/apps/openmw/mwgui/imagebutton.hpp b/apps/openmw/mwgui/imagebutton.hpp index 9fce12da1b..f531e22469 100644 --- a/apps/openmw/mwgui/imagebutton.hpp +++ b/apps/openmw/mwgui/imagebutton.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_IMAGEBUTTON_H #define MWGUI_IMAGEBUTTON_H -#include "MyGUI_ImageBox.h" +#include namespace MWGui { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 044a2b2a43..cd1ff7ebbd 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -29,8 +29,8 @@ namespace MWGui void notifyNextPage(MyGUI::Widget* _sender); void notifyPrevPage(MyGUI::Widget* _sender); - MyGUI::EditPtr mLeftTextWidget; - MyGUI::EditPtr mRightTextWidget; + MyGUI::EditBox* mLeftTextWidget; + MyGUI::EditBox* mRightTextWidget; MWGui::ImageButton* mPrevBtn; MWGui::ImageButton* mNextBtn; std::vector mLeftPages; diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index 0bafced97b..d60e9b6877 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -1,6 +1,9 @@ #include "list.hpp" -#include +#include +#include +#include +#include using namespace MWGui; using namespace MWGui::Widgets; diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index d07d49de63..38797e7798 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -1,7 +1,12 @@ #ifndef MWGUI_LIST_HPP #define MWGUI_LIST_HPP -#include +#include + +namespace MyGUI +{ + class ScrollView; +} namespace MWGui { diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 0ee042e326..b8a34c457e 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -247,7 +247,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan std::vector::const_iterator it; for(it = buttons.begin(); it != buttons.end(); ++it) { - MyGUI::ButtonPtr button = mButtonsWidget->createWidget( + MyGUI::Button* button = mButtonsWidget->createWidget( MyGUI::WidgetStyle::Child, std::string("MW_Button"), dummyCoord, @@ -301,7 +301,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; - std::vector::const_iterator button; + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { buttonCord.left = left; @@ -349,7 +349,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan int top = textButtonPadding + buttonTopPadding + textSize.height; - std::vector::const_iterator button; + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; @@ -371,7 +371,7 @@ void InteractiveMessageBox::enterPressed() { std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) @@ -393,7 +393,7 @@ void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) { mMarkedToDelete = true; int index = 0; - std::vector::const_iterator button; + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { if(*button == pressed) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 4be8bc5b79..149aa7e7f1 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -2,7 +2,6 @@ #define MWGUI_MESSAGE_BOX_H #include -#include #include "window_base.hpp" @@ -10,6 +9,13 @@ #undef MessageBox +namespace MyGUI +{ + class Widget; + class Button; + class EditBox; +} + namespace MWGui { class InteractiveMessageBox; @@ -61,7 +67,7 @@ namespace MWGui MessageBoxManager& mMessageBoxManager; int mHeight; const std::string& mMessage; - MyGUI::EditPtr mMessageWidget; + MyGUI::EditBox* mMessageWidget; int mFixedWidth; int mBottomPadding; int mNextBoxPadding; @@ -81,9 +87,9 @@ namespace MWGui void buttonActivated (MyGUI::Widget* _widget); MessageBoxManager& mMessageBoxManager; - MyGUI::EditPtr mMessageWidget; - MyGUI::WidgetPtr mButtonsWidget; - std::vector mButtons; + MyGUI::EditBox* mMessageWidget; + MyGUI::Widget* mButtonsWidget; + std::vector mButtons; int mTextButtonPadding; int mButtonPressed; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 71a4d1b3e4..1436995c53 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -41,7 +41,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); // Set up next/previous buttons - MyGUI::ButtonPtr prevButton, nextButton; + MyGUI::Button *prevButton, *nextButton; setText("GenderChoiceT", mWindowManager.getGameSettingString("sRaceMenu2", "Change Sex")); getWidget(prevButton, "PrevGenderButton"); @@ -73,11 +73,11 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials")); getWidget(mSpellPowerList, "SpellPowerList"); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); @@ -89,7 +89,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) void RaceDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) @@ -134,7 +134,7 @@ void RaceDialog::setRaceId(const std::string &raceId) if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) { mRaceList->setIndexSelected(i); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); break; } @@ -256,7 +256,7 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); const std::string *raceId = mRaceList->getItemDataAt(_index); if (boost::iequals(mCurrentRaceId, *raceId)) @@ -331,7 +331,7 @@ void RaceDialog::updateRaces() void RaceDialog::updateSkills() { - for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) + for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } @@ -369,7 +369,7 @@ void RaceDialog::updateSkills() void RaceDialog::updateSpellPowers() { - for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) + for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 6195569065..efd08f4395 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -85,11 +85,11 @@ namespace MWGui MyGUI::ListBox* mRaceList; MyGUI::ScrollBar* mHeadRotate; - MyGUI::WidgetPtr mSkillList; - std::vector mSkillItems; + MyGUI::Widget* mSkillList; + std::vector mSkillItems; - MyGUI::WidgetPtr mSpellPowerList; - std::vector mSpellPowerItems; + MyGUI::Widget* mSpellPowerList; + std::vector mSpellPowerItems; int mGenderIndex, mFaceIndex, mHairIndex; int mFaceCount, mHairCount; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 50dc26e428..50508cc5f0 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -86,11 +86,11 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); } - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); } @@ -309,7 +309,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId void ReviewDialog::updateSkillArea() { - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index aac609a646..4f41ec42d6 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -91,7 +91,7 @@ namespace MWGui std::map mSkillWidgetMap; std::string mName, mRaceId, mBirthSignId; ESM::Class mKlass; - std::vector mSkillWidgets; //< Skills and other information + std::vector mSkillWidgets; //< Skills and other information }; } #endif diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 70ceed8579..0fa4127b55 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -67,7 +67,7 @@ StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) for (int i = 0; i < ESM::Skill::Length; ++i) { mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)nullptr)); + mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); } MyGUI::WindowPtr t = static_cast(mMainWidget); @@ -419,7 +419,7 @@ void StatsWindow::updateSkillArea() { mChanged = false; - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 6619680fa0..3befc1f002 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -67,11 +67,11 @@ namespace MWGui SkillList mMajorSkills, mMinorSkills, mMiscSkills; std::map > mSkillValues; std::map mSkillWidgetMap; - std::map mFactionWidgetMap; + std::map mFactionWidgetMap; FactionList mFactions; ///< Stores a list of factions and the current rank std::string mBirthSignId; int mReputation, mBounty; - std::vector mSkillWidgets; //< Skills and other information + std::vector mSkillWidgets; //< Skills and other information std::set mExpelled; bool mChanged; diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index c193948330..9265cadf94 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -13,7 +13,7 @@ TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) getWidget(mTextEdit, "TextEdit"); mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); @@ -23,7 +23,7 @@ TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) void TextInputDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp index 6499902815..29de7388b2 100644 --- a/apps/openmw/mwgui/text_input.hpp +++ b/apps/openmw/mwgui/text_input.hpp @@ -30,7 +30,7 @@ namespace MWGui void onTextAccepted(MyGUI::Edit* _sender); private: - MyGUI::EditPtr mTextEdit; + MyGUI::EditBox* mTextEdit; }; } #endif diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c7acf568d1..261a7f8bd8 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -439,7 +439,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) effectsWidget->setWindowManager(mWindowManager); effectsWidget->setEffectList(info.effects); - std::vector effectItems; + std::vector effectItems; effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, info.isPotion ? Widgets::MWEffectList::EF_NoTarget : 0); totalSize.height += coord.top-6; totalSize.width = std::max(totalSize.width, coord.width); @@ -459,7 +459,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) enchantWidget->setWindowManager(mWindowManager); enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); - std::vector enchantEffectItems; + std::vector enchantEffectItems; int flag = (enchant->mData.mType == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, flag); totalSize.height += coord.top-6; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index f932c1f034..8857ecfa39 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -31,10 +34,10 @@ void MWGui::Widgets::fixTexturePath(std::string &path) /* MWSkill */ MWSkill::MWSkill() - : mManager(nullptr) + : mManager(NULL) , mSkillId(ESM::Skill::Length) - , mSkillNameWidget(nullptr) - , mSkillValueWidget(nullptr) + , mSkillNameWidget(NULL) + , mSkillValueWidget(NULL) { } @@ -103,7 +106,7 @@ void MWSkill::initialiseOverride() assignWidget(mSkillNameWidget, "StatName"); assignWidget(mSkillValueWidget, "StatValue"); - MyGUI::ButtonPtr button; + MyGUI::Button* button; assignWidget(button, "StatNameButton"); if (button) { @@ -123,10 +126,10 @@ void MWSkill::initialiseOverride() /* MWAttribute */ MWAttribute::MWAttribute() - : mManager(nullptr) + : mManager(NULL) , mId(-1) - , mAttributeNameWidget(nullptr) - , mAttributeValueWidget(nullptr) + , mAttributeNameWidget(NULL) + , mAttributeValueWidget(NULL) { } @@ -195,7 +198,7 @@ void MWAttribute::initialiseOverride() assignWidget(mAttributeNameWidget, "StatName"); assignWidget(mAttributeValueWidget, "StatValue"); - MyGUI::ButtonPtr button; + MyGUI::Button* button; assignWidget(button, "StatNameButton"); if (button) { @@ -215,8 +218,8 @@ void MWAttribute::initialiseOverride() /* MWSpell */ MWSpell::MWSpell() - : mWindowManager(nullptr) - , mSpellNameWidget(nullptr) + : mWindowManager(NULL) + , mSpellNameWidget(NULL) { } @@ -226,7 +229,7 @@ void MWSpell::setSpellId(const std::string &spellId) updateWidgets(); } -void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags) +void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -234,7 +237,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: const ESM::Spell *spell = store.get().search(mId); MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); - MWSpellEffectPtr effect = nullptr; + MWSpellEffectPtr effect = NULL; std::vector::const_iterator end = spell->mEffects.mList.end(); for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) { @@ -286,7 +289,7 @@ MWSpell::~MWSpell() /* MWEffectList */ MWEffectList::MWEffectList() - : mWindowManager(nullptr) + : mWindowManager(NULL) , mEffectList(0) { } @@ -297,11 +300,11 @@ void MWEffectList::setEffectList(const SpellEffectList& list) updateWidgets(); } -void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags) +void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, bool center, int flags) { // We don't know the width of all the elements beforehand, so we do it in // 2 steps: first, create all widgets and check their width.... - MWSpellEffectPtr effect = nullptr; + MWSpellEffectPtr effect = NULL; int maxwidth = coord.width; for (SpellEffectList::iterator it=mEffectList.begin(); @@ -320,7 +323,7 @@ void MWEffectList::createEffectWidgets(std::vector &effects, M } // ... then adjust the size for all widgets - for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) + for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) { effect = static_cast(*it); bool needcenter = center && (maxwidth > effect->getRequestedWidth()); @@ -375,9 +378,9 @@ SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() - : mWindowManager(nullptr) - , mImageWidget(nullptr) - , mTextWidget(nullptr) + : mWindowManager(NULL) + , mImageWidget(NULL) + , mTextWidget(NULL) , mRequestedWidth(0) { } @@ -495,9 +498,9 @@ void MWSpellEffect::initialiseOverride() MWDynamicStat::MWDynamicStat() : mValue(0) , mMax(1) -, mTextWidget(nullptr) -, mBarWidget(nullptr) -, mBarTextWidget(nullptr) +, mTextWidget(NULL) +, mBarWidget(NULL) +, mBarTextWidget(NULL) { } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 7cbb5e53ac..597bcbe324 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -2,11 +2,17 @@ #define MWGUI_WIDGETS_H #include "../mwworld/esmstore.hpp" - -#include - #include "../mwmechanics/stat.hpp" +#include +#include +#include + +namespace MyGUI +{ + class ImageBox; +} + namespace MWBase { class WindowManager; @@ -118,7 +124,8 @@ namespace MWGui MWBase::WindowManager *mManager; ESM::Skill::SkillEnum mSkillId; SkillValue mValue; - MyGUI::WidgetPtr mSkillNameWidget, mSkillValueWidget; + MyGUI::Widget* mSkillNameWidget; + MyGUI::Widget* mSkillValueWidget; }; typedef MWSkill* MWSkillPtr; @@ -160,7 +167,8 @@ namespace MWGui MWBase::WindowManager *mManager; int mId; AttributeValue mValue; - MyGUI::WidgetPtr mAttributeNameWidget, mAttributeValueWidget; + MyGUI::Widget* mAttributeNameWidget; + MyGUI::Widget* mAttributeValueWidget; }; typedef MWAttribute* MWAttributePtr; @@ -186,7 +194,7 @@ namespace MWGui * @param spell category, if this is 0, this means the spell effects are permanent and won't display e.g. duration * @param various flags, see MWEffectList::EffectFlags */ - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags); + void createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags); const std::string &getSpellId() const { return mId; } @@ -230,7 +238,7 @@ namespace MWGui * @param center the effect widgets horizontally * @param various flags, see MWEffectList::EffectFlags */ - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags); + void createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, bool center, int flags); protected: virtual ~MWEffectList(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1138f62faa..7d5b6af6ec 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -3,7 +3,7 @@ #include #include -#include "MyGUI_UString.h" +#include #include #include diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index e5a164b818..07fbafa7de 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -1,9 +1,10 @@ -#include -#include -#include - #include "manager.hpp" +#include +#include + +#include + using namespace OEngine::GUI; /* diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index c0f98da88b..9443fba018 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -1,6 +1,8 @@ #ifndef OENGINE_MYGUI_MANAGER_H #define OENGINE_MYGUI_MANAGER_H +#include + namespace MyGUI { class Gui; From e1882dce32c96ff773a1dbc5b92f7eef1cb71cde Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 3 Mar 2013 13:02:41 +0000 Subject: [PATCH 0576/1483] correcting a bug: player orientation wasn't stored correctly, and objects orientation wasn't properly retrived. --- apps/openmw/mwrender/renderingmanager.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fe3dc776d1..b214fd8009 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -273,16 +273,21 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot Ogre::Quaternion xr(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X); Ogre::Quaternion yr(Ogre::Radian(rot.y), Ogre::Vector3::UNIT_Y); Ogre::Quaternion zr(Ogre::Radian(rot.z), Ogre::Vector3::UNIT_Z); - Ogre::Quaternion newo = adjust ? (xr * yr * zr) * ptr.getRefData().getBaseNode()->getOrientation() : xr * yr * zr; - rot.x = newo.x; - rot.y = newo.y; - rot.z = newo.z; + + Ogre::Quaternion xref(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yref(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zref(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); + + Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; + rot.x = newo.getPitch().valueRadians();// newo.x;Ogre::Quaternion:: + rot.y = newo.getYaw().valueRadians();//newo.y; + rot.z = newo.getRoll().valueRadians(); //newo.z; ptr.getRefData().getBaseNode()->setOrientation(newo); } else if(isPlayer) { rot.x = mPlayer->getPitch(); - rot.z = mPlayer->getYaw(); + rot.z = -mPlayer->getYaw(); } else if (adjust) { From 7fb2ff18a39d5347811ae6ca0cd7eca635688f58 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 3 Mar 2013 13:06:45 +0000 Subject: [PATCH 0577/1483] Fix bug induced by previous commit (player orientation wasn't stored correctly), and fix NPC not beeing able to move with certain angles (like angle Z 70) because the trace function was hitting NPC own hitboxes. The solution prposed here is a little hacky, but i works. Need a little clean up(mBody shouldn't be public) --- apps/openmw/mwworld/physicssystem.cpp | 15 ++++++++------- libs/openengine/bullet/physic.hpp | 3 ++- libs/openengine/bullet/trace.cpp | 11 ++++++++++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 65cbc1164e..90c090f593 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -99,7 +99,7 @@ namespace MWWorld if(!physicActor || !physicActor->getCollisionMode()) { // FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why? - return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + return position + (Ogre::Quaternion(Ogre::Radian( refpos.rot[2]), Ogre::Vector3::UNIT_Z)* Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement; @@ -109,12 +109,13 @@ namespace MWWorld bool onground = false; float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); - Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); + Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); + physicActor->mBody->translate(btVector3(0,0,1000)); Ogre::Vector3 velocity; if(!gravity) { - velocity = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + velocity = (Ogre::Quaternion(Ogre::Radian( refpos.rot[2]), Ogre::Vector3::UNIT_Z)* Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement / time; @@ -127,9 +128,7 @@ namespace MWWorld if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) onground = true; } - - velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * - movement / time; + velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::UNIT_Z)*movement / time; velocity.z += physicActor->getVerticalForce(); } @@ -148,6 +147,7 @@ namespace MWWorld // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; + //std::cout << newPosition.x << " "; remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions @@ -191,7 +191,8 @@ namespace MWWorld } physicActor->setOnGround(onground); physicActor->setVerticalForce(!onground ? clippedVelocity.z - time*627.2f : 0.0f); - + physicActor->mBody->translate(btVector3(0,0,-1000)); + //std::cout << position.x << " " << newPosition.x << " " << position.y << " " << newPosition.y << std::endl; return newPosition; } }; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index bd5d3d50aa..6a7150fca5 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -129,9 +129,10 @@ namespace Physic void operator delete (void * Data) { _aligned_free (Data); } #endif + OEngine::Physic::RigidBody* mBody; + private: - OEngine::Physic::RigidBody* mBody; Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 7664eb418e..3abe13da43 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -8,6 +8,7 @@ #include "physic.hpp" +#define BIT(x) (1<<(x)) enum traceWorldType { @@ -24,6 +25,14 @@ enum collaborativePhysicsType Both_Physics = 3 // This object has both kinds of physics (example: activators) }; +enum collisiontypes { + COL_NOTHING = 0, //dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); From ac0a23a68d644610789f00ad1912f5443aa88937 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 14:53:47 +0100 Subject: [PATCH 0578/1483] Fix initialization problem --- files/materials/objects.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 88ca2d1524..6495b0cb4f 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -146,7 +146,7 @@ #if VERTEX_LIGHTING float3 lightDir; float d; - + lightResult = float3(0,0,0); @shForeach(@shGlobalSettingString(num_lights)) lightDir = lightPosition[@shIterator].xyz - (shInputPosition.xyz * lightPosition[@shIterator].w); d = length(lightDir); From 5951abfae2ec518e03bb343d8958b7b72c68cfe6 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 3 Mar 2013 13:59:38 +0000 Subject: [PATCH 0579/1483] fix some script instructions --- apps/openmw/mwscript/transformationextensions.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 2dd8f3e160..8222ef1509 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -148,15 +148,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -241,15 +241,15 @@ namespace MWScript if(axis == "x") { - runtime.push(ptr.getCellRef().mPos.pos[0]); + runtime.push(ptr.getRefData().getPosition().pos[0]); } else if(axis == "y") { - runtime.push(ptr.getCellRef().mPos.pos[1]); + runtime.push(ptr.getRefData().getPosition().pos[1]); } else if(axis == "z") { - runtime.push(ptr.getCellRef().mPos.pos[2]); + runtime.push(ptr.getRefData().getPosition().pos[2]); } else throw std::runtime_error ("invalid axis: " + axis); From 11f21a19886fdb010fe6f67c1c42ececb95ee4b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 15:10:40 +0100 Subject: [PATCH 0580/1483] Weather update should be before renderer update --- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f8efcdbd4e..cddcda68b2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -974,6 +974,8 @@ namespace MWWorld void World::update (float duration, bool paused) { + mWeatherManager->update (duration); + mWorldScene->update (duration, paused); float pitch, yaw; @@ -981,8 +983,6 @@ namespace MWWorld mRendering->getPlayerData(eyepos, pitch, yaw); mPhysics->updatePlayerData(eyepos, pitch, yaw); - mWeatherManager->update (duration); - performUpdateSceneQueries (); updateWindowManager (); From 867b22ce19cad53e4e5ba3aaf9f2826b7273fe43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 15:11:19 +0100 Subject: [PATCH 0581/1483] Fix a terrain glitch --- apps/openmw/mwrender/terrain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 212dd94c3b..438366873c 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -42,7 +42,8 @@ namespace MWRender // We don't want any pixel error at all. Really, LOD makes no sense here - morrowind uses 65x65 verts in one cell, // so applying LOD is most certainly slower than doing no LOD at all. - mTerrainGlobals->setMaxPixelError(0); + // Setting this to 0 seems to cause glitches though. :/ + mTerrainGlobals->setMaxPixelError(1); mTerrainGlobals->setLayerBlendMapSize(32); From 002830e13bc8ce0f9a882b9b225959f3cbfb2120 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 15:11:45 +0100 Subject: [PATCH 0582/1483] Make sure render textures are inactive when in a cell without water --- apps/openmw/mwrender/refraction.cpp | 5 +++++ apps/openmw/mwrender/refraction.hpp | 1 + apps/openmw/mwrender/water.cpp | 6 ++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 15575362b5..bb2d888658 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -99,4 +99,9 @@ namespace MWRender } } + void Refraction::setActive(bool active) + { + mRenderTarget->setActive(active); + } + } diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp index de47d6e43b..b9ab8deac2 100644 --- a/apps/openmw/mwrender/refraction.hpp +++ b/apps/openmw/mwrender/refraction.hpp @@ -25,6 +25,7 @@ namespace MWRender void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void setUnderwater(bool underwater) {mIsUnderwater = underwater;} + void setActive (bool active); void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index d112e17b2c..c116a6384b 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -372,9 +372,9 @@ void Water::updateVisible() { mWater->setVisible(mToggled && mActive); if (mReflection) - { mReflection->setActive(mToggled && mActive); - } + if (mRefraction) + mRefraction->setActive(mToggled && mActive); } void Water::update(float dt, Ogre::Vector3 player) @@ -424,6 +424,8 @@ void Water::applyRTT() mRefraction = new Refraction(mCamera); mRefraction->setHeight(mTop); } + + updateVisible(); } void Water::applyVisibilityMask() From f0e3463e9bb636e303b5d77834848f058e8b715a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 16:50:10 +0100 Subject: [PATCH 0583/1483] Disable assertion for comparing iterators from different containers (Bug #605) --- apps/openmw/mwworld/containerstore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index eb2a14d5b8..8a7884e9e0 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -548,7 +548,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStoreIterator::operator++ (int bool MWWorld::ContainerStoreIterator::isEqual (const ContainerStoreIterator& iter) const { - assert (mContainer==iter.mContainer); + if (mContainer!=iter.mContainer) + return false; if (mType!=iter.mType) return false; From c9fefc7f5d245541c5d24def1e26ac7bb3cd8776 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 19:28:11 +0100 Subject: [PATCH 0584/1483] Simpler, more lightweight underwater effect, changed colors to match vanilla better --- apps/openmw/mwgui/settingswindow.cpp | 13 ----- apps/openmw/mwgui/settingswindow.hpp | 1 - apps/openmw/mwrender/renderconst.hpp | 3 ++ apps/openmw/mwrender/renderingmanager.cpp | 40 ++++++--------- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/videoplayer.cpp | 6 ++- apps/openmw/mwrender/water.cpp | 24 --------- apps/openmw/mwrender/water.hpp | 3 +- files/CMakeLists.txt | 1 - files/materials/objects.shader | 58 ++++------------------ files/materials/openmw.configuration | 1 + files/materials/terrain.shader | 55 ++------------------ files/materials/underwater.h | 4 +- files/materials/water.mat | 8 --- files/materials/water.shader | 30 ++--------- files/mygui/openmw_settings_window.layout | 7 --- files/settings-default.cfg | 2 - files/water/underwater_dome.mesh | Bin 22585 -> 0 bytes 18 files changed, 46 insertions(+), 212 deletions(-) delete mode 100644 files/water/underwater_dome.mesh diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index ebeb42ab2e..04856c3ed9 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -129,7 +129,6 @@ namespace MWGui getWidget(mStaticsShadows, "StaticsShadows"); getWidget(mMiscShadows, "MiscShadows"); getWidget(mShadowsDebug, "ShadowsDebug"); - getWidget(mUnderwaterButton, "UnderwaterButton"); getWidget(mControlsBox, "ControlsBox"); getWidget(mResetControlsButton, "ResetControlsButton"); getWidget(mInvertYButton, "InvertYButton"); @@ -141,7 +140,6 @@ namespace MWGui mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mInvertYButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); - mUnderwaterButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mShadersButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadersToggled); mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -236,7 +234,6 @@ namespace MWGui mReflectObjectsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect statics", "Water") ? "#{sOn}" : "#{sOff}"); mReflectActorsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect actors", "Water") ? "#{sOn}" : "#{sOff}"); mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}"); - mUnderwaterButton->setCaptionWithReplacing(Settings::Manager::getBool("underwater effect", "Water") ? "#{sOn}" : "#{sOff}"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); //mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); @@ -267,7 +264,6 @@ namespace MWGui if (!Settings::Manager::getBool("shaders", "Objects")) { mRefractionButton->setEnabled(false); - mUnderwaterButton->setEnabled (false); mShadowsEnabledButton->setEnabled(false); } @@ -389,10 +385,6 @@ namespace MWGui Settings::Manager::setBool("shader", "Water", newState); else if (_sender == mRefractionButton) Settings::Manager::setBool("refraction", "Water", newState); - else if (_sender == mUnderwaterButton) - { - Settings::Manager::setBool("underwater effect", "Water", newState); - } else if (_sender == mReflectObjectsButton) { Settings::Manager::setBool("reflect misc", "Water", newState); @@ -459,10 +451,6 @@ namespace MWGui { Settings::Manager::setBool("shaders", "Objects", false); - mUnderwaterButton->setCaptionWithReplacing("#{sOff}"); - - mUnderwaterButton->setEnabled(false); - // refraction needs shaders to display underwater fog mRefractionButton->setCaptionWithReplacing("#{sOff}"); mRefractionButton->setEnabled(false); @@ -485,7 +473,6 @@ namespace MWGui mReflectTerrainButton->setEnabled(true); mRefractionButton->setEnabled(true); - mUnderwaterButton->setEnabled(true); mShadowsEnabledButton->setEnabled(true); } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 55cc0a8704..fc1ec9e365 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -50,7 +50,6 @@ namespace MWGui MyGUI::Button* mReflectTerrainButton; MyGUI::Button* mShadersButton; MyGUI::Button* mShaderModeButton; - MyGUI::Button* mUnderwaterButton; MyGUI::Button* mRefractionButton; MyGUI::Button* mShadowsEnabledButton; diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index cc3cbee291..1d2cdf1ead 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -56,6 +56,9 @@ enum VisibilityFlags RV_Debug = 512, + // overlays, we only want these on the main render target + RV_Overlay = 1024, + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 943208a66b..c8b5926d92 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -133,8 +133,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setGlobalSetting ("lighting", "true"); sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); sh::Factory::getInstance ().setGlobalSetting ("terrain_num_lights", Settings::Manager::getString ("num lights", "Terrain")); - sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); + sh::Factory::getInstance ().setGlobalSetting ("render_refraction", "false"); sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); @@ -355,16 +355,7 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); - /* - if (world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)) - { - mFogColour = Ogre::ColourValue(0.18039, 0.23137, 0.25490); - mFogStart = 0; - mFogEnd = 1500; - } - */ - - applyFog(); + applyFog(world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)); if(paused) { @@ -529,16 +520,20 @@ void RenderingManager::configureFog(const float density, const Ogre::ColourValue mRendering.getCamera()->setFarClipDistance ( Settings::Manager::getFloat("max viewing distance", "Viewing distance") / density ); } -void RenderingManager::applyFog () +void RenderingManager::applyFog (bool underwater) { - mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); - - mRendering.getViewport()->setBackgroundColour (mFogColour); - - mWater->setViewportBackground (mFogColour); - - sh::Factory::getInstance ().setSharedParameter ("viewportBackground", - sh::makeProperty (new sh::Vector3(mFogColour.r, mFogColour.g, mFogColour.b))); + if (!underwater) + { + mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); + mRendering.getViewport()->setBackgroundColour (mFogColour); + mWater->setViewportBackground (mFogColour); + } + else + { + mRendering.getScene()->setFog (FOG_LINEAR, Ogre::ColourValue(0.18039, 0.23137, 0.25490), 0, 0, 1000); + mRendering.getViewport()->setBackgroundColour (Ogre::ColourValue(0.18039, 0.23137, 0.25490)); + mWater->setViewportBackground (Ogre::ColourValue(0.18039, 0.23137, 0.25490)); + } } void RenderingManager::setAmbientMode() @@ -784,11 +779,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); rebuild = true; } - else if (it->second == "underwater effect" && it->first == "Water") - { - sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); - rebuild = true; - } else if (it->second == "shaders" && it->first == "Objects") { sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 02d796fddf..49cde25a31 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -208,7 +208,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList sh::Factory* mFactory; void setAmbientMode(); - void applyFog(); + void applyFog(bool underwater); void setMenuTransparency(float val); diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index a0dedb6bc2..2cbc85cd38 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -17,6 +17,8 @@ #include "../mwsound/sound_decoder.hpp" #include "../mwsound/sound.hpp" +#include "renderconst.hpp" + #ifdef _WIN32 #include @@ -1067,9 +1069,9 @@ VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) mBackgroundNode->attachObject(mBackgroundRectangle); mRectangle->setVisible(false); - mRectangle->setVisibilityFlags(0x1); + mRectangle->setVisibilityFlags(RV_Overlay); mBackgroundRectangle->setVisible(false); - mBackgroundRectangle->setVisibilityFlags(0x1); + mBackgroundRectangle->setVisibilityFlags(RV_Overlay); } VideoPlayer::~VideoPlayer() diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c116a6384b..49836535f6 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -4,14 +4,10 @@ #include #include #include -#include -#include -#include #include #include "sky.hpp" #include "renderingmanager.hpp" -#include "compositors.hpp" #include "ripplesimulation.hpp" #include "refraction.hpp" @@ -224,16 +220,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mWater->setMaterial(mMaterial); - /* - Ogre::Entity* underwaterDome = mSceneManager->createEntity ("underwater_dome.mesh"); - underwaterDome->setRenderQueueGroup (RQG_UnderWater); - mUnderwaterDome = mSceneManager->getRootSceneNode ()->createChildSceneNode (); - mUnderwaterDome->attachObject (underwaterDome); - mUnderwaterDome->setScale(10000,10000,10000); - mUnderwaterDome->setVisible(false); - underwaterDome->setMaterialName("Underwater_Dome"); - */ - setHeight(mTop); sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); @@ -379,21 +365,11 @@ void Water::updateVisible() void Water::update(float dt, Ogre::Vector3 player) { - /* - Ogre::Vector3 pos = mCamera->getDerivedPosition (); - pos.y = -mWaterPlane.d; - mUnderwaterDome->setPosition (pos); - */ - mWaterTimer += dt; sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - //if (player.y <= mTop) - { - //mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); - } mSimulation->update(dt, Ogre::Vector2(player.x, player.y)); if (mReflection) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index ddf6ef7ab7..633a306640 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -25,6 +25,7 @@ namespace Ogre class SceneNode; class Entity; class Vector3; + class Rectangle2D; struct RenderTargetEvent; } @@ -108,8 +109,6 @@ namespace MWRender { Ogre::SceneNode *mWaterNode; Ogre::Entity *mWater; - //Ogre::SceneNode* mUnderwaterDome; - bool mIsUnderwater; bool mActive; bool mToggled; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index c29d917b89..9e65b516b7 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1,7 +1,6 @@ project(resources) set(WATER_FILES - underwater_dome.mesh water_nm.png circle.png ) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 6495b0cb4f..37ff178437 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -16,7 +16,7 @@ #endif -#define UNDERWATER @shGlobalSettingBool(underwater_effects) && LIGHTING +#define UNDERWATER @shGlobalSettingBool(render_refraction) #define HAS_VERTEXCOLOR @shPropertyBool(has_vertex_colour) @@ -242,18 +242,8 @@ #endif #if UNDERWATER - - shUniform(float, waterLevel) @shSharedParameter(waterLevel) - - shUniform(float4, lightDirectionWS0) @shAutoConstant(lightDirectionWS0, light_position, 0) - - shSampler2D(causticMap) - - shUniform(float, waterTimer) @shSharedParameter(waterTimer) - shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) + shUniform(float, waterLevel) @shSharedParameter(waterLevel) shUniform(float, waterEnabled) @shSharedParameter(waterEnabled) - - shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #endif #if VERTEX_LIGHTING @@ -305,13 +295,7 @@ #endif #if UNDERWATER - float3 waterEyePos = float3(1,1,1); - // NOTE: this calculation would be wrong for non-uniform scaling - float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); - caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.z >= waterLevel || waterEnabled != 1.f) - caustics = float3(1,1,1); + float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif #if !VERTEX_LIGHTING @@ -358,41 +342,17 @@ #if FOG float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - #if UNDERWATER - // regular fog only if fragment is above water - if (worldPos.z > waterLevel || waterEnabled != 1.f) - #endif + +#if UNDERWATER + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); +#else shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); +#endif + #endif // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); - -#if UNDERWATER - float fogAmount = (cameraPos.z > waterLevel) - ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) - : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); - - float3 eyeVec = normalize(cameraPos.xyz-worldPos); - - float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); - waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = float3(0.0,1.0,0.85) *waterSunGradient * 0.5; - - float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); - waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = ( float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; - watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; - - - float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); - watercolour *= darkness; - - float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); -#endif } #endif diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index 21ac9416bf..b953a91311 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -8,6 +8,7 @@ configuration water_reflection configuration water_refraction { viewproj_fix true + render_refraction true } configuration local_map diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index ea54bb24c6..af5be42cd5 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -21,7 +21,7 @@ #define NEED_DEPTH 1 #endif -#define UNDERWATER @shGlobalSettingBool(underwater_effects) && LIGHTING +#define UNDERWATER @shGlobalSettingBool(render_refraction) #define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) @@ -210,14 +210,6 @@ #if UNDERWATER shUniform(float, waterLevel) @shSharedParameter(waterLevel) - shUniform(float4, lightDirectionWS0) @shAutoConstant(lightDirectionWS0, light_position, 0) - - shSampler2D(causticMap) - - shUniform(float, waterTimer) @shSharedParameter(waterTimer) - shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) - - shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #endif @@ -242,17 +234,7 @@ float3 caustics = float3(1,1,1); #if UNDERWATER - - float3 waterEyePos = float3(1,1,1); - // NOTE: this calculation would be wrong for non-uniform scaling - float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); - caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.z >= waterLevel) - caustics = float3(1,1,1); - - - + float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif @@ -353,41 +335,14 @@ float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); #if UNDERWATER - // regular fog only if fragment is above water - if (worldPos.z > waterLevel) - #endif + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); + #else shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); + #endif #endif // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); - -#if UNDERWATER - float fogAmount = (cameraPos.z > waterLevel) - ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) - : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); - - float3 eyeVec = normalize(cameraPos.xyz-worldPos); - - float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); - waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; - - float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); - waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; - float3 waterext = float3(0.6, 0.9, 1.0);//water extinction - watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; - - - float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); - watercolour *= darkness; - - float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); -#endif } #endif diff --git a/files/materials/underwater.h b/files/materials/underwater.h index a760202fa2..8474f299d0 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -1,4 +1,6 @@ -#define VISIBILITY 1500.0 // how far you can look through water +#define UNDERWATER_COLOUR float3(0.18039, 0.23137, 0.25490) + +#define VISIBILITY 1000.0 // how far you can look through water #define BIG_WAVES_X 0.3 // strength of big waves #define BIG_WAVES_Y 0.3 diff --git a/files/materials/water.mat b/files/materials/water.mat index 372058f0ac..3ea6a2c2bf 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -56,11 +56,3 @@ material Water } } } - - -material Underwater_Dome -{ - parent openmw_objects_base - - depth_write off -} diff --git a/files/materials/water.shader b/files/materials/water.shader index 59b9e5a43f..793cdc95e3 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -272,38 +272,16 @@ #if REFRACTION shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; #else - shOutputColour(0).xyz = reflection + specular * sunSpecular.xyz; + shOutputColour(0).xyz = shLerp(reflection, float3(0.18039, 0.23137, 0.25490), (1.0-fresnel)*0.5) + specular * sunSpecular.xyz; #endif // fog - if (isUnderwater == 1) - { - float waterSunGradient = dot(-vVec, -lVec); - waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; - - float waterGradient = dot(-vVec, float3(0.0,-1.0,0.0)); - waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; - float3 waterext = float3(0.6, 0.9, 1.0);//water extinction - watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - - float darkness = VISIBILITY*2.0; - darkness = clamp((cameraPos.z+darkness)/darkness,0.2,1.0); - - - float fog = shSaturate(length(cameraPos.xyz-position.xyz) / VISIBILITY); - shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, watercolour * darkness, shSaturate(fog / waterext)); - } - else - { - float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); - } + float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); #if REFRACTION shOutputColour(0).w = 1; #else - shOutputColour(0).w = shSaturate(fresnel + specular); + shOutputColour(0).w = shSaturate(fresnel*2 + specular); #endif } diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 00d4eea110..693c5a9cb5 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -280,13 +280,6 @@ - - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 044cc34061..2dee5ac88d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -138,8 +138,6 @@ reflect small statics = false reflect actors = false reflect misc = false -underwater effect = false - [Sound] # Device name. Blank means default device = diff --git a/files/water/underwater_dome.mesh b/files/water/underwater_dome.mesh deleted file mode 100644 index 64ca569c22a04110e7913505c427f0087cef51c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22585 zcmZu(b$k`a_uVA~0)Zewf`tIVH8>=125SjW+?@cyr4-i&cUoH9DH@h)b7#(6nb{a=Th@;5+ofUjPhF#WbR81?Q`-Sy#mcu% zX_Sa>YT&olJS~<+ zy2gyGZY|GNU+?($h3k2zEG&=VcRp_TS;{G=>=c3eBV5;FgXH-vPr7e}JfG#!Q_Jd& z8Be=f;rYquJ$1AEX||!B-UX{Gmd^bGuKL~pB5M%{m(M#{5fzvH^q@JA`{6{fAle}?Pj z)7q$&+fwVB_q$2`^NV|UCbmwH`U$7<>!Jgjs7Z#uly48a;yN7I#WN@>LA6*~-Ws^D zj1G+%s-D+KuCuKBRqA`5M|rMnd?xirtMv)Osp-$ptMJd~rGBT*WjyT{mzMg&Mg-|YHi52D)W^`TQa^V>faj0ljimmZOX>87+3_k{(N$93-)F2Vhi@t=-@WUq+b>6u ze)xEg>b>MwwXbe+56A!F^cU8yK2cJC=idSPUXueV+l8r8p13v2_3xcTDeqU=?cRSe zPW8MDWj)^2PwFpR>Zb>0xTa42T};Y*eog5rQuKEzUzMwy`{M?G zT{Q14b*|e}SCt`|r2bzAYg$hdhe-W@*ZS%&1sGYV{TMrFItni2<&ksp?(@IO@i+g-@ zli_a^)E0BDM;5719YU1)D;IoKJyII_N!2z|e?zXV5xv4ZQom+Yu)Fg7q`F$!cZ$4V z`>CI1&BLXA?@P>gf9{?_=dS-u<@hyJ`d_`#1XsY)Nz(sRf8TM>tsbD8HM@`b*G%+# zXKS3Rooln`x77PgR^c*%I&bCcD(9lHGJeC_UvX{Ba$Ux6;L-|Kj_@E|)i|#*3|T1i zBX9pC%DCer^JCk@7S`j=Idsce$JN@CaWem6-)2yG2WOJ`_n^jL>%`{VI{4Z?m9^Ia zncpi@=2La%=9l@M`OGA1aYO+<^08ax&VEVw(|b%A)h9OPPxxOaah=tvTScAFX^Fb? zG>NP))WiDuEo6NelI0)E|NF|iP?MRe)8gc^e%;vAPI;o*d&-B+P(MxFVJ)5>sny>T zWqsoM$$5JAb7xr}hZfyw?T@afvz8sAo}^4I>+j7CUDfHf-DUk9@OihD=}j};EN5F; z|2XPX!Go(6ddT`cZDWF!v_*T}V@_pdUHzPl={JwQ+t+Yj@HAf&s6oW zez87zykTx5sUMm;z!STyw=ObzlB{2BA9=j$U_EJH&XN9}WdmC3^FJy1vVWAAb~VY4v-WQ5X8@zRH(1gYYZt(O%cJ ziGzh-u5J0O{PogmzkW{??FRYD^|Qj<0>aPb^>4T{?n|k6wtc0l_(cl8Gp_b^WlOhC z_#JsO+8r3_t5-#QQ2lchl5$?d>;ER@yxz8ab-!Vs6zu|^&ueH@8hJjiYLmY%e&e0G zd-tP@>m#pLSR-j4uVep7r(cG@R^%P~$7{&&$Q4@X;{qWj;>{`(e zul-)PB6~~44gV)7(4vKzx4eS`IbH03_)-RbT*YDO`k@-RU&3RJn&rCAE zc^0cf!oZnoBBJ1au`ORygsrB@QImcCj zdB=qxymt7msQ53uX6fHt*J*c1>@)dAJKgS=FyR-kYf^R4_tx%F#qORH{_@%*Z)xE# zuMKMS)W!a^#Qu}N^aFYvE-n1!^~$_KdUdv~io7TPxek!`^bffX6p87hE2@WLzgeH_ z0C`XUkn6zjWryoDsqTyYX8Y*JkoWZOxDI^U-%0;e=dmL1$$zc`+Zf+*8}0k$hN)@y*+1Gp+I{wqen9JlAlQ#2 zns%T1p&vlIPyNsjC<*->&Eun~AL^I(fp%Z~NB9BerM$Z42_H?n&+(xjK)cWJDLOEd zC+zPcy6MoQn(Ge7m;9sM=lIeOSm7z9|1R#UY4_c_1l2TV9yMIYUeOw;aje$o%1-RJzIAF%y>O}$`za?O5oe$x-2-RJzKACP2z zLp`FGpQha>Kj;V0?vo$%1LFQ|rS~>Yp=tNYFUBdf`{Wn>fNbtgI^c(tns%T3r5`}M zPySws>h1{}+DETz?5}C}$zR4nwEN^Q{Q&Z}#fVgzaUtt7PGnrj`iv9X7wf6}7R#j> z7qUL%IL3vn&p2_|h(Y?utWZt=mF;63$GDB{V;tAvRD1nH=3vdZjQwMr#<+~}8{@PF zHJW2?Wz(Ej)DQc|xQqH>9Ol=wp58byNHeaYei>&muA+V!XJt+wsrP=(s5$RBK3sno zH*tIzM}<_Wq~qoWYQ{wzU&cv{i#WbhqN{lB{99gUXq!&cu5o^h!ura%hx3DRP?mjR z+OI+y&A5j1i*XL)8qP1qIj*OLbjjSQHTlQ+N&km&3+E@}n5k_;^@e=@nsEu|H{%q> zC7j=kQ@;8J>!`9RgkR(b$C+^l`N25kHo`NcRRbW=LLVX&`e z+(3SE92hr{pNu2o|Mu6xt9>-%0`i-20^F>?}9YIWaN%Go}~NvzNIF;41KJFVV+*-y&ZKkqzb{}_kue2`K1 zy5=wC)DPo4)~9|L=XLudn_l%WK+36K`kySPei=ue|2da#5RhKVIX;Y2SQpo`(El9wlSWmipPA5>ih7G7rP&lfTTveEFxN9($sUl=I({ zbe24hLH;t2lUTU7F4-cS{C7L}ue|)v)V-OW-#3!{m)wobf8<8~?h=u@A$}kHcRTp6y!_w&zLNfKR2lN$?cl%i^8aI{ ziaPRRaq{0y{`dNi|H{k%MUP79fA-Ng7`&rANhIX~!Mf&a?O|C#v< z=obZYk^gQ7|6N}GXIYb5S6i8#{C7L}@AC3LZL1u5cda1u-|gVP%gg_2WrOtQv>C{M zw}byKFaOsU3)CxKry>8{4*t8m{7+LYKv#L-PyWX{`0w)ae}9)0I_^nw@;~0e{|GPt zPs~lKeLwnW*ncUv?Z3-w|EIWpbop~hrF{KXDUDvzJCOEY^kdt9<+cB(&jspceS>KKErqf6HP2WqfJ>2R#kZJ31Di{kJ$jmrv0}Z_Fv{F?f=7L#dW_S6>0x1hy9oNP5WP~Ng2JX zTxHsSi~O+dzwm?hzeeqFeWGn7?Z4%)|H3cY|JeA-x<>kXwEvdF{tJI;|7-7v)N{Ht zqy4wYf7|{Gf5rYcsiy-+MQQl|Qs4IfHTh5fe_F+|+Lb?AW8Ibdw*L?Ck{=dvG+y9sOMgRYLx{SKQ>HHf0 zzsyhD|Cjkm|3CS^>2$gSxitKLi~P6!f0^I(|Icg;&_ix#lle{l+y1}sgZ_VkMgIEl zLYXxDf8m$y|10vJ{{Q~Pe)`#@w6gw?pSJ%m{G|WCZndv|Wcq9P|8DZ%_Wy<7^#7-9 zPofKt@zsd?rQDAHrJV8qmU*VGhZunCBcE@_|BCAim&X_8gakq$BzF+KaBtPz4Oy2sszjUkpFi4FZyNt zf9PgPeQSBBM%*vsW5@q8K8*iU-ASb*%NEv%|7Coc2SD7fxxO?0zx6Rdzf4+EBkq^^ zVaNZP_JQ$#uHbaKW9|wX^TKk(|C;uN@qcXBKpix*l1AJw^V5$1HSH7Q|L6l5b&mm& z8gYlrZ#({%`OWx0wsw$CdA6QL+%NpF>VNhQ*5JL=xAT8epLu|7 zpHu1r!+z4>z3|`8|4Du30qzB*(u;pVtXT4cw9n4}N&A=w==M5=9y`3V2JfYRcK%QL z$2>rjmwvi=x7HfG7ya1zKhY2K0A+prbY!MR8oU?%+W9}xFY^FP!;{GW_3^8lBZ`XY`Gm+_^2;QRvbWqvRZ5co8y?&Dip zgZDDO?EIgmePJG;Sh=J+^l1@Ue>gww{GZHE<^jr&_tDW=@@ep1=C_^ylljd&z|}iR zbdP~K#lDaqcK%QJ!8}0PN=fu6BZ~&_E!uxO|0n!n9-#IzQ;&*GFa8htY3KihpUeaF zNowlNT~lfBUifY2|AgPn0~GIS=ws!QG5;^+cK%<=nFr|5;fr#kocCfBApm7xMt2&mXGD9-TGfeh=+G^8m2>!e8bArq8*r z4mSM>^Yg#GFYbfE?hAjJ2YB}Rj*6%~LL=^%`u6^?)Mp;xN~?I~>*=ZC_j~9+a32eC zztm?QpnHLTRA|A$8gak0kMSqserX@`0ACV!tNV33XvF=}KYM>x`o}y#?D+#K%ZBFC zKkA2h0L1;GALaor)jg)Ndg^J!{T}*P_Wr8qw^NN0R`=1TRHrVHvi`{W{NMhmj1Thw z-*r5%CQYlP5%|M&3|Q&5{~%zsxUt ze^cfc^8gJx-cc(`6c+!7^OO8T+%NNU*vYHzv8^7cDGNh2;(nRm_Wq>IZ{`8se4nVQ zR0`G@SK$Zwg}7h%!8|~AzvpU;Uyw%JFZ{Ci7lmKU18jG{QWIcb8Gn(V_Wq&plX-vx zQSVfRr~Vpozwq1M9~6GK7`ZgQzwt@Me(=?Z`=y*?jJRLQaT`;7*LziBw6DZ}d_Kz& z_sjEHzWT;Xl@U1`#QoAfmLu+$_OU$E`$Uy>Vp{P($$yq3?w9_tyveJ3s%^eZ8gakq zhvkU-ML#V6`@#+N?0PowKdE1qBkmXdvfLVfNtKSzr4jeb_^=#tzl;ydU#C5zemk6B z>>tOM<%s)bd|4jT?wI;Ju$V^NFY|-{hPYqm2k(p5-LJaOEv>PCFZKohW+3jD`Ni@^ zpFHaAfN+htU*;#v5%C13hPYq&%lp~=$16|A-cJ6zk@xfRUrpK8Qq8E-%*+26<^df1SDqp+^}b7#lmBi9 z|JD8F168jNb)EcoBk$+szZx`ag6dEu(#e0fga7Jtj~U80V`V4*-N^fS`LCM(zE}lz zs_5ju8+ku3|5b~$Yt*}-(mKum`0vK~2rvIt#|LpLHe)d-|J@G$tCj8Cs$WzAC;#2Z z`^o&ekn4--SWRm;fjLVTwn`{q{N8ZoN|A-Ph z-l`&JlRE8xJo5ft`|nES^G5yi-p6VG-H7|W_TQDP!()~Aaq@5WpLqbp{a*X;y1L<} zdUD_2Y5(2G`+M!bT6pffD)Bsx)Bd}W_xIX=HS^Rlm5?rj)Baly`>$5U>`|E`gPiu? zLfr4Q|El1FZEE16>`wb{IqbhG@NB(m8Jf#!|1HG*Ui+_({kTkpoyhC7|CYo4t6hC( ztL>gbPWx{m?)Tb%m1oB!HSJz;r~S7a_Fw(*;}F%OO&Q(ffA-%(-0!vjszO|AwN-~Z z?Z1V%-)sL>tVgM`(T+dut4%Bt}{}$qY zsSp2OUrc)5mETiF)<3Qn%mZNG&+Gr|8Dqw{23HJs`u`T5ci9I;s2|Yo_=cBygW|--*Wi> zs{FYLs@8#=PXFIR+%Mw`|6c`+nx&$%Wq11jmc##7UuQ2<U4)w z%J;JWH~)X_!@X|A{lYK!|0-_YRTYc;I`f~l|L;cJFZ_i6?<%(bfvR=K*XjSe5%&wf z;s3k3#=cTB-Xw9x|8B(nQqJp_?Jw1dv!*ltcO&kX=kq$~c~i2J?qzk1msR$UBE?Tr5|NBpm&_sv(~Wzy)h|BL@E#QicqcpWxps#@MSo!;`l z_}@a@FZPAkhzY}0?}dTR_}@a@FY}Yv!zJ3N*f$xS@xO(*U*Ne<9`crzwnFK;O=)_rLqL;RCfH&E8>3PFRz_0&u|?tk;@zZ$1o3o zxL^3oYmPr3M#Rktb>{yp^4`w>>7&QmyGHc(_vZg%=m#P0m-<`>{1dZBY+Rnong6pK z`9B>Ny5Ci=UP@>F&m!;b{GTpd#$T0=OySJ`S%~{ZKU@bkXDFe1HuQ7m|19#J`4z4M zzRMb@nZuI{|LFfS4}iGeoBz|5O7~T1HYIcB|19#J`5mqUcl{=+hWC7(`9BMBzc>G< zC-0rDV#9o$`9F)iXZ+7~;NZO#s_DR_&itQ+xL@Wc*MT3V#i;|we7@!XT*w2E_snl| z9VmNbrz%iL_P53VXP%k7XMUXPz|4P+s>-91IP-rNd2i?clz+R6>eDsTng4T>_sq|6 z9oTmDt_rDaI`e;S@}Bv9t^+<*UaH6yhBN=~M%*vu^aHw}eDkF*iu)5>Uzi6#-0#i* zt4i1Is&jvQR*w9?g}C3F|Cjdd?)FJJ^8Xg%e(4|mfJJdf70)*~^8Xg%e$fy8fGqoW zs>g5Se1tduZz1j%{n8IeJuyyoTk%dg^8Xg%eiR$MgdpBoo3L z{Xbpc#cfyP@q3ha|L+{~0Eqj&`+vId)gbjE{~?^u`?mk*LEJC;VI0tSe1uxj>9}(2 z|9P`uBD7)ziB-lw<$TqTg@t|LLrCVpYVeJ3N2m-T$)?_j~vM^!Q$z zRmxWnlw<$TLfr4&|5K$4C#Wx{5`|xkk2%hW`@Q>rDrCWNwQlNj<=FqT5chlc|5UDH zm(;cjua#r}&yBcW_{liH|I|Iz?b18t*#C1Q?)UEhxq8RHR0jrqQt<5zd;eeddAU9? z53p^`E2S%ZkaF_ho(G1#|F72m^+5Txd?n@f{=dZ7_Wr;6ZoySGs_zpiXaDSZXxRJz zYEi3Gs>{IpQf}}6OMQF)Uv0awUv+MOQ_30td-tL2{eRsrPrPcK<+7C9`~Om(qV_+sdS(AOF8Ek?H_ez@BiyM zb0(-cyLL*sz5g#c4txJ!zYXuFdZgGU<;-t+^Kj%p^8jOqHdZq({3Yeg|1l51=iB@L zI&^4hm9N5TDJTEEc{qFjUyn>otERtPB<1%0ztp$)|MiH~r(I9)$-5GKY>b@;@b3TX zL-k{D&S#?Xp8vUxJfP$JkM10kO`ZL-jk3>u#Mu0|?EQaTaMNSgQcop0zs~kC59m1m zqw|bIe&Fq3@?XyX*!;Kb{eOM=d@I##`b6^Id;W*~x2PZTf6x8F>P6L=(O9|_h!ufE=`5()1{zs=dy-mHlwNK99aei_ilzBgU|6ix>vqw!|c%1zAp8p~L zz2|>aVfQg*2A(JX<$RpYfA9Gp6?XExs#E?RJ^w@g zyY2mdwIcelx>Wla`R_gdL;icu|G4t{zEPt~y>p)bqy2Z=`~R-z?zc(}eIxC2*nfFG z^8g9wo~rVf9@G9y`?wF_IRB?MUb?4Z3f`jq_n!Zw{kQD>f7N==HFd1+1=@en5BC8a z=l@jPkaKE(t>bb&lKSO7vE%%oj!Sl2MSa>s`>*W%f7*YG{Kxq}J-XgLwX^wlIe+Z1 z|1!SJ1DIvp>O=bt%6tBg`v8vffBNkHIF;_sGC7~k`DNRGnP1EUY&{aIYCf7x`>*W% zf7*YUpUeZ?Y_?c6FFTp`U)lTrwEr@{Y5x~T%uw6<45j^7KkdIo{?q=?7}r7-?;Wh{b5~ybFZ^X5pv|Rl6*%mr z%W?jf{=diT|8E}mn@SaN&c%H{t{=Al501+Izpm*&UfoYO+Qof8wvYCg`+oNRziyvq zp}OIh{@eNALf8l7zMt3sUudmV`FfRcp8uu)FYjm3{~xnugL?l%6X*F~`v0O|`v0Fk zZBYdZ^q2F$93R{Nm+@g9;9P=7ZOc0G+xg!)*avi+|J70D_p6|jv%a1GWt`_Y|Ev2{ zIHoE;U*aM=*Jpa%5U;4-R|4Fjvs&d*B&h!6_|3yEH|D($!s+3C; zWPHefp3`ug|5tmPKTyRlZFZjjXZ$bY!#u!)c6U^&^|9a1|6lJkm+`;H-v8HI3f)i} zQZ7)4{}t^&^8noUxA*^b@hg{AyMt2|=7r+?;{4#gzrFvj{UXk*+S`Xa&;K+2_t^XY z`rc2c)PcNhzMcPn*Yg15e-F>MF#ez4;+UE>JHmPXpYgx&gYkd!JqJ|keL>Fi|BU~I zUyT3%-nLuCx4P{@+%NpMrKtSpr>&i8+q|C8}y9^gvV7phTsU-%c_-v43#&!c>DYvuvm*I%lH!V?wG{m?#ee(~H7 z=LhouD{8-1n&u1Qh=l;ll<^g6UH?_O*y>IXT+4+BIAM*gsmz#Rbsf%L&*gxh0csI`F=I`|3tsc1H8SRQC~>bMsfY&_%ILPcz;?A?iZ*t%p9)Z_sja;80Ua_ z?w{*B^8lkurqj3fO_lYP^MiQ+$NSH!x`DI*<^t#Y&D{SJ{xc7-bYk(JKs;{{-4Zm<^j^b_0ucoz!t#26aIr=j`xpUy)q@&Cjw45-!JC= zpYV%$fR8R;9ar_T#9!nm^8k+bhh4vR_tEuh-v9P~u)Y5${Kk6#5yKXkI=nRE_ez~J zEnGg2DaDOO9M+oDvBqT0hWPO1iw@kSQb)Yw4fZY9Hc^MS$SZ2NCna2 z3cw1G3ZN$yffXU;M-Rh+;gIs7=MlgNNO_?V7tjSM6q-^%1t||SsDT<%ZfLd=uo9$P z&~_z!LX66gDhXCLs^D8%u!>O?wUuC1qZ*#-60Bx?hhK{j{Lc6utq2$V-l&e&RTQjl zM55Id1S5?a=uLUS8b(d@vYcQ|qZWE!RJh3sbF{B^xOHF`HAk{((ngW|bs)?30 z12%(H11)Y2Yz`?BJ!t`K0jWBA*b>+h()Z|jD_|=~-$5g-fvq7`gQnU5+d!%c4Ymcg zg;WKaZ3k=zsWPt*x>_J!07HTwbkLF$Po_6PQd)C0dX05||r zceG$2a3G{^XxSj(AV^)&;=#bdkh-8JLx4jdbw&?|0*6BCgq{xr4ucd8jSL44htv_8 z8UY*usRK0lGw^3f?V;HiU<{-vXgda<5Mv~y7{QUoD17T@!BNI&)E*%?+8BeU4i_9_ zjK!}F6C7)dLo0>~jx)xibwdQl8xzp#!GaTviRjHB!HLEs^m3r!Bx5pqKR|G@F$G%b zFF3`R3T^choN7#i7W)cLGk$?~`w0GG{EE*n#&qCx<2T$*GkypD4rv-{&H&DUG!;*r z37iRO3Vvx8a2BM=Xu)jYY)F&PvN^yxkS3zVbAfXqO+ZiP0p~#)j~>nk&WAJ(JzoG^ z0BI~VvJkis(imuJ5pWTt(a_*x;9^LlpxGtBC6Go!+e`2XF_uDFBDmD}1K(OK_=m9! zwHFC4GnV723k8=OEAVRz1Xma<(Te$kD~(lX-8{in#%i>BuHb4T7QLAx7;CISFJ}v` zG1j8@vjo=~>!6jHg6oVwp{*H$e;Vtd#oq4F=Kzwp^$Yy@sJ{>I&UBMuk` zX+3Ig0&arzC!Y8Z@E=I)@JpM4n<1@53$_5aKw5*AZ3S+H6pI#b18#$~8a>$#+zx3K zdbk6)1JX+LJRTSiX$3Um2D%|Fho&r`1!);H=mB~l{Q=GH1nz{i6x!a2Pl&M#(oVr$ z#%_GeBe>g0Ky6Df!PtYRx&`+bd+}@Wf_sg9XvGe}ea3#YZoA-q;{aN{P4Iwm5WU$d zc+fb6UTzUQWE@8CHwzv%jzBB_2p%zxLR*^zj~d6I#W=xZ#&KwOqu_Dl1U|=&lfaY4 zzqmVQoC2PLbPP3515ZObiYJ}{o`G}(zjPLO7Sds~;2iKAq(f-gdEj|S2hrjSzzdKL zpeGlB7a{FO4=({PLE49&Uj|-=v=WZZcok9tGQxFmSjxQEtV6uf8L zN2@Og-ZvhgH|GT(7!T3QbAk_zN9g@o!AHhpXyuIHVS#qWXdA>Bt$J^(*Jx`!Tq1b&2c7d`(3`~>L^H1Zkv8PaWN>I?7-q+8J7SKwDj zH=$X>yovw6;x2?Pt{GyOkN`l_Ok#e)H;GA1AM-Qn5Pi&~<|jOhnAG$&KjJrtzGgD> z1Ad#B%uH^+N1KSrO+WJ;+Dh~@Qo zOX!H0+6*wCLwCdgGmZHIIwhtt)8doHOb1M7rpH}?83+u76oC2}fEggA#&a_QGeSy* z-^&Ed1j!%m$PCO3DJ9w$1Pp?d0`1NM%mT>|{mBZ<3Mo1InGKi?QZn>EJ1{#WU+5(V zFbAZh&{r@p7?Kb4m=l;2QW9u31Q-GdcSZ>A;GaVZF^Rd%-1t^b!Q5sZ)D9NRV}|0X zIRrz^y!f^3f_cq+Xhk-`d}e;ME~{XEvjAG1MX-Qb5WNW!ENB)&FEa}kG7F>knFI@) zMWB_8fapX#9cA76tEPeVyIafSQ=7M zJh2S045T9XrLw@XkP4#(<$&cN6++9(1It4yh!$4>R)AChJ*fz+2q`~$7!C}Fln*_R z07gK{3yrvdE=Zx!lmaS9d7wcJ)R1yRtCfJ2AmxI#E8#B0z?l$SiIvSN_?8x|Vpc_M zC0Nz0hNrp&tC`>7*CGVJGrvbG!UexKtD|)l1*@BpXmtg_NV5idQ(mx!Srff1Cs@<0 zh2EDHtY!WHt&|b`!K@8!l@_dR)`1pF3Dz;|Lc3vtbzfU5SI2A!YzV0i zYBmBkf>aw%Yz%A+=?DB$6JQfawa|j5z^0IDqGip1%^=l4i<<+RLyAOCS^!%>s*WDE z1h$0qJ$l{>*b35j&`4`wYe?0gsW!kikg7t1ZGmkeRe@I90oy^U3~jf=U5F6{shvrT zGTY-@Z3Ww#9ZgIx7%&zE7 zGr_KAH}tZpU^lZndf!B_yV(O;X)M^o>lg!EJ{Q$wq<`ih9zu**eDzw#4aH=^CTI?%0&HM%0 z?IZY$`71uZnA3sN&EIf0&HNqsJEUo-IRiKY(o{TgCU7RCDfp#Xz*&$cqXn~pvms4F z%jN**K$?ga&jrqfGyy%C2b>3KJbE}EI3LnD^n3wu0i?0e$U@*kNMoR>MZiUnMni*( zfr}xHf>xIRmp~c`Z7;!Hh_MvX5|g;p`~%-wEcl1H47C>tE;E{n=9~Z3j|k~ zE76Mif-B8cXx%))Rpx56damGVGZwv>BN%J0K`&+nmP zftw+%MGLk7w?JBhmTd)Yg%pbxZv$?Fv>H9x4%`lD6?(V>xC7Ek^gJFI4`~H7;s&}Q zEr+Hopap3eH0S|(ApHTY?gZ|Hv=rLjiMtSE7o?pgahJIp-|`6VHWN_W5==1n;HhrG zJ?38gTD;(1b01o-zowhA6J522S^1P_^q(fiGUhs`6< z%0Gff%%jlOCc&fTF=#PP@R)fV+TAF4+&qELaq}ebr1>xIj+v)`ryw0e&C|fskdESs zXMkrQ9l#_K-vRMT?Jl+lmHE0173r)8(O^%ybfs>w0#|SA;t|z*G=LL^CrG^P4K39 z3$?Eb-ZF3FsaFJVn|JVQmj&;bchQPVf_Ke(Xx&A@d**$#`hwtn^8tEuUhskW5WPGn z_|SZW-k%kGWIl#g&Imp>6QQlsf{Er6Xz`Tb6Z0vwds6VJ`3#?@=5ye4^9Amnm@k1Z zAw5COSHM@067j^>z}Ju-b~&9{3*8ee~o5@B^fK z=;24;M@VfBV3xC41h(X8~f5dMPGa--s0l!Vmfc)}%w27D=dFOX% zD={td(QnZQVgT~gZ_qblD&((UqtC>Y$ZNlXE{J|cGUFw5L`-HRHJ(Fv#H5Cg@d7#} v`k>)yEBP7BmK(q3#+8S#_{TVTwg0fL{9zXSn>Lo@!Z(bi*@*vNLjL~%QsK$) From f1d35b73b80c361724efe518de3742f998bd3103 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 19:52:20 +0100 Subject: [PATCH 0585/1483] Cleanup --- apps/openmw/mwrender/localmap.hpp | 3 --- apps/openmw/mwrender/refraction.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 14 -------------- apps/openmw/mwrender/renderingmanager.hpp | 2 -- apps/openmw/mwrender/terrainmaterial.cpp | 6 ------ apps/openmw/mwrender/water.cpp | 17 ++++++++--------- files/materials/objects.shader | 13 ++----------- files/materials/terrain.shader | 7 ++----- files/settings-default.cfg | 6 +++--- 9 files changed, 16 insertions(+), 54 deletions(-) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 9c82258f95..72e637d9ab 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -117,9 +117,6 @@ namespace MWRender int mCellX, mCellY; Ogre::AxisAlignedBox mBounds; std::string mInteriorName; - - // maps texture name to according camera settings - std::map mCameraSettings; }; } diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index bb2d888658..d590dbf4c3 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -33,7 +33,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.180, 0.235, 0.22352)); + vp->setBackgroundColour (Ogre::ColourValue(0.18039, 0.23137, 0.25490)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c8b5926d92..382ec6557e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -121,9 +121,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const //mRendering.getScene()->setCameraRelativeRendering(true); // disable unsupported effects - //const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - if (!waterShaderSupported()) - Settings::Manager::setBool("shader", "Water", false); if (!Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("enabled", "Shadows", false); @@ -504,9 +501,6 @@ void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) color.setAsABGR (mCell.mCell->mAmbi.mFog); configureFog(mCell.mCell->mAmbi.mFogDensity, color); - - //if (mWater) - // mWater->setViewportBackground (Ogre::ColourValue(0.8f, 0.9f, 1.0f)); } void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) @@ -854,14 +848,6 @@ void RenderingManager::windowClosed(Ogre::RenderWindow* rw) Ogre::Root::getSingleton ().queueEndRendering (); } -bool RenderingManager::waterShaderSupported() -{ - //const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - //if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) - //return false; - return true; -} - void RenderingManager::applyCompositors() { } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 49cde25a31..e40672ada9 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -184,8 +184,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::Viewport* getViewport() { return mRendering.getViewport(); } - static bool waterShaderSupported(); - void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); ///< see MWRender::LocalMap::getInteriorMapPosition diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index d5e531f869..8a568883df 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -119,10 +119,6 @@ namespace MWRender shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); } - // caustics - sh::MaterialInstanceTextureUnit* caustics = p->createTextureUnit ("causticMap"); - caustics->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue("water_nm.png"))); - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty(new sh::StringValue( Ogre::StringConverter::toString(numBlendTextures + numLayers + 2)))); @@ -156,8 +152,6 @@ namespace MWRender // shadow --freeTextureUnits; - --freeTextureUnits; // caustics - // each layer needs 1.25 units (1xdiffusespec, 0.25xblend) return static_cast(freeTextureUnits / (1.25f)); } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 49836535f6..2801e64942 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -210,6 +210,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mWater = mSceneMgr->createEntity("water"); mWater->setVisibilityFlags(RV_Water); mWater->setCastShadows(false); + mWater->setRenderQueueGroup(RQG_Alpha); mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); @@ -380,6 +381,8 @@ void Water::applyRTT() { delete mReflection; mReflection = NULL; + delete mRefraction; + mRefraction = NULL; // Create rendertarget for reflection //int rttsize = Settings::Manager::getInt("rtt size", "Water"); @@ -389,16 +392,12 @@ void Water::applyRTT() mReflection = new PlaneReflection(mSceneMgr, mSky); mReflection->setParentCamera (mCamera); mReflection->setHeight(mTop); - } - mWater->setRenderQueueGroup(RQG_Alpha); - delete mRefraction; - mRefraction = NULL; - - if (Settings::Manager::getBool("refraction", "Water")) - { - mRefraction = new Refraction(mCamera); - mRefraction->setHeight(mTop); + if (Settings::Manager::getBool("refraction", "Water")) + { + mRefraction = new Refraction(mCamera); + mRefraction->setHeight(mTop); + } } updateVisible(); diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 37ff178437..7c7a604cc1 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -260,13 +260,6 @@ float3 lightDir; float3 diffuse = float3(0,0,0); float d; - -#if HAS_VERTEXCOLOR - // ambient vertex colour tracking, FFP behaviour - //float3 ambient = colourPassthrough.xyz * lightAmbient.xyz; -#else - //float3 ambient = materialAmbient.xyz * lightAmbient.xyz; -#endif // shadows only for the first (directional) light #if SHADOWS @@ -288,8 +281,6 @@ - float3 caustics = float3(1,1,1); - #if (UNDERWATER) || (FOG) float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePositionPassthrough,1)).xyz; #endif @@ -311,10 +302,10 @@ #if @shIterator == 0 #if (SHADOWS || SHADOWS_PSSM) - diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow * caustics; + diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow; #else - diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * caustics; + diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0); #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index af5be42cd5..0120629fc4 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -230,9 +230,6 @@ #endif - - float3 caustics = float3(1,1,1); - #if UNDERWATER float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif @@ -312,10 +309,10 @@ #if @shIterator == 0 #if (SHADOWS || SHADOWS_PSSM) - diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow * caustics; + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow; #else - diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * caustics; + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0); #endif diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 2dee5ac88d..6ff7fb4328 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -94,7 +94,7 @@ fps = 0 crosshair = true [Objects] -shaders = false +shaders = true # Max. number of lights that affect objects. Setting to 1 will only reflect sunlight # Note: has no effect when shaders are turned off @@ -127,9 +127,9 @@ fog end factor = 1.0 num lights = 8 [Water] -shader = false +shader = true -refraction = false +refraction = true rtt size = 512 reflect terrain = true From 6911868f2af56b48f2884e65092e0bbb52e14f56 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sun, 3 Mar 2013 15:58:26 -0600 Subject: [PATCH 0586/1483] File->close and File->exit menu items added. Exit uses closeAllWindows() to ensure ViewManager::closeRequest is called on the last open window. Exit will close all open windows but the last one in cases of active save operation or modified file. --- apps/opencs/editor.cpp | 4 +++- apps/opencs/view/doc/view.cpp | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e2df365a29..98b67142a5 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -58,5 +58,7 @@ int CS::Editor::run() { mStartup.show(); + QApplication::setQuitOnLastWindowClosed (true); + return QApplication::exec(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 0a8759fa1f..78eba78801 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" @@ -40,10 +41,15 @@ void CSVDoc::View::setupFileMenu() connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); + QAction *close = new QAction (tr ("&Close"), this); + connect (close, SIGNAL (triggered()), this, SLOT (close())); + file->addAction(close); + QAction *exit = new QAction (tr ("&Exit"), this); - connect (exit, SIGNAL (triggered()), this, SLOT (close())); + connect (exit, SIGNAL (triggered()), QApplication::instance(), SLOT (closeAllWindows())); file->addAction(exit); + } void CSVDoc::View::setupEditMenu() From 5e50436a946f7efd9bb1fe281fd0a0ceb7513369 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Mar 2013 14:19:02 -0800 Subject: [PATCH 0587/1483] Convert some BooleanValues to StringValues --- components/nifogre/ogre_nif_loader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9652fd6055..17cac73455 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -752,10 +752,10 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::BooleanValue(!((alphaFlags>>13)&1)))); + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(!((alphaFlags>>13)&1) ? "on" : "off"))); - instance->setProperty("depth_check", sh::makeProperty(new sh::BooleanValue(depthFlags&1))); - instance->setProperty("depth_write", sh::makeProperty(new sh::BooleanValue((depthFlags>>1)&1))); + instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); // depth_func??? sh::Factory::getInstance()._ensureMaterial(matname, "Default"); From 8e076386994bf6e16deeaeea39a8c753a96489fa Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Mon, 4 Mar 2013 12:21:38 +0100 Subject: [PATCH 0588/1483] Update the trading offer on "max sale" button click --- apps/openmw/mwgui/tradewindow.cpp | 61 +++++++++++++++---------------- apps/openmw/mwgui/tradewindow.hpp | 4 ++ 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 290310760e..e3cf8ea3a7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -64,6 +64,7 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); + mMaxSaleButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onMaxSaleButtonClicked); mIncreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonPressed); mIncreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); mDecreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonPressed); @@ -191,21 +192,7 @@ namespace MWGui } // check if the merchant can afford this - int merchantgold; - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) - { - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mNpdt52.mGold == -10) - merchantgold = ref->mBase->mNpdt12.mGold; - else - merchantgold = ref->mBase->mNpdt52.mGold; - } - else // ESM::Creature - { - MWWorld::LiveCellRef* ref = mPtr.get(); - merchantgold = ref->mBase->mData.mGold; - } - if (mCurrentBalance > 0 && merchantgold < mCurrentBalance) + if (mCurrentBalance > 0 && getMerchantGold() < mCurrentBalance) { // user notification MWBase::Environment::get().getWindowManager()-> @@ -293,6 +280,12 @@ namespace MWGui mWindowManager.removeGuiMode(GM_Barter); } + void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) + { + mCurrentBalance = getMerchantGold(); + updateLabels(); + } + void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { mBalanceButtonsState = BBS_Increase; @@ -341,22 +334,7 @@ namespace MWGui mTotalBalance->setCaption(boost::lexical_cast(-mCurrentBalance)); } - int merchantgold; - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) - { - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mNpdt52.mGold == -10) - merchantgold = ref->mBase->mNpdt12.mGold; - else - merchantgold = ref->mBase->mNpdt52.mGold; - } - else // ESM::Creature - { - MWWorld::LiveCellRef* ref = mPtr.get(); - merchantgold = ref->mBase->mData.mGold; - } - - mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(merchantgold)); + mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(getMerchantGold())); } std::vector TradeWindow::getEquippedItems() @@ -468,4 +446,25 @@ namespace MWGui mWindowManager.removeGuiMode(GM_Barter); mWindowManager.removeGuiMode(GM_Dialogue); } + + int TradeWindow::getMerchantGold() + { + int merchantGold; + + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + MWWorld::LiveCellRef* ref = mPtr.get(); + if (ref->mBase->mNpdt52.mGold == -10) + merchantGold = ref->mBase->mNpdt12.mGold; + else + merchantGold = ref->mBase->mNpdt52.mGold; + } + else // ESM::Creature + { + MWWorld::LiveCellRef* ref = mPtr.get(); + merchantGold = ref->mBase->mData.mGold; + } + + return merchantGold; + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index c1d31917ba..ea749f5a24 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -74,6 +74,7 @@ namespace MWGui void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender); + void onMaxSaleButtonClicked(MyGUI::Widget* _sender); void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); @@ -93,6 +94,9 @@ namespace MWGui void updateLabels(); virtual void onReferenceUnavailable(); + + private: + int getMerchantGold(); }; } From 215d45aaf7e83fdc1cd1b9957a3c0e53ac80c57a Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Mon, 4 Mar 2013 12:17:48 +0100 Subject: [PATCH 0589/1483] Make trade window's "max sale" button clickable The HBox widget above it was stealing the input events. --- files/mygui/openmw_trade_window.layout | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index d38377f987..ecc794c928 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -51,10 +51,6 @@ - - - - @@ -66,6 +62,10 @@ + + + + From 48b3f1e0cf1e118480d795bf797d0c4fbacc8e2b Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 4 Mar 2013 12:08:35 +0000 Subject: [PATCH 0590/1483] Clean up. But still a little hacky --- apps/openmw/mwworld/physicssystem.cpp | 6 ++---- libs/openengine/bullet/physic.cpp | 4 ++++ libs/openengine/bullet/physic.hpp | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 90c090f593..316e57b789 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -110,7 +110,7 @@ namespace MWWorld float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); - physicActor->mBody->translate(btVector3(0,0,1000)); + physicActor->enableCollisions(false); Ogre::Vector3 velocity; if(!gravity) @@ -147,7 +147,6 @@ namespace MWWorld // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; - //std::cout << newPosition.x << " "; remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions @@ -191,8 +190,7 @@ namespace MWWorld } physicActor->setOnGround(onground); physicActor->setVerticalForce(!onground ? clippedVelocity.z - time*627.2f : 0.0f); - physicActor->mBody->translate(btVector3(0,0,-1000)); - //std::cout << position.x << " " << newPosition.x << " " << position.y << " " << newPosition.y << std::endl; + physicActor->enableCollisions(true); return newPosition; } }; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index f993ce68e2..677d75f334 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -37,6 +37,8 @@ namespace Physic Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map + //mBody->setCollisionFlags(COL_NOTHING); + //mBody->setMas } PhysicActor::~PhysicActor() @@ -50,6 +52,8 @@ namespace Physic void PhysicActor::enableCollisions(bool collision) { + if(collision && !collisionMode) mBody->translate(btVector3(0,0,-1000)); + if(!collision && collisionMode) mBody->translate(btVector3(0,0,1000)); collisionMode = collision; } diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 6a7150fca5..e579e35468 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -129,10 +129,10 @@ namespace Physic void operator delete (void * Data) { _aligned_free (Data); } #endif - OEngine::Physic::RigidBody* mBody; private: - + + OEngine::Physic::RigidBody* mBody; Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; From 3384d92761a921562b7ec0b15444007ef11fd18e Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 4 Mar 2013 12:28:43 +0000 Subject: [PATCH 0591/1483] oups introduced a bug.. --- apps/openmw/mwscript/transformationextensions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8222ef1509..d86a6e3486 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -119,15 +119,15 @@ namespace MWScript if (axis == "x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()); } else if (axis == "y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()); } else if (axis == "z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); From 65081f5520b733b235b87a9b98e5f6afbb331962 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Mar 2013 13:59:06 +0100 Subject: [PATCH 0592/1483] added variant class --- apps/opencs/view/world/vartypedelegate.hpp | 2 + components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 12 - components/esm/loadglob.hpp | 1 + components/esm/loadgmst.hpp | 1 + components/esm/loadinfo.hpp | 1 + components/esm/variant.cpp | 256 ++++++++++++++++++++ components/esm/variant.hpp | 85 +++++++ components/esm/variantimp.cpp | 262 +++++++++++++++++++++ components/esm/variantimp.hpp | 179 ++++++++++++++ 10 files changed, 788 insertions(+), 13 deletions(-) create mode 100644 components/esm/variant.cpp create mode 100644 components/esm/variant.hpp create mode 100644 components/esm/variantimp.cpp create mode 100644 components/esm/variantimp.hpp diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp index 621dd316b3..c8493f0291 100644 --- a/apps/opencs/view/world/vartypedelegate.hpp +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_VARTYPEDELEGATE_H #define CSV_WORLD_VARTYPEDELEGATE_H +#include + #include "enumdelegate.hpp" namespace CSVWorld diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00342e2ac8..0c75123cbf 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (esm loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat - loadweap records aipackage effectlist spelllist + loadweap records aipackage effectlist spelllist variant variantimp ) add_component_dir (misc diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 143d90034a..bd86f9ba03 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -9,18 +9,6 @@ namespace ESM // Pixel color value. Standard four-byte rr,gg,bb,aa format. typedef int32_t Color; -enum VarType -{ - VT_Unknown, - VT_None, - VT_Short, // stored as a float, kinda - VT_Int, - VT_Long, // stored as a float - VT_Float, - VT_String, - VT_Ignored -}; - enum Specialization { SPC_Combat = 0, diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 6111648a63..96d2fcaf42 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -4,6 +4,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index f7aec5c76c..12f212081c 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -4,6 +4,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index f1decb9c63..ca08c3b55b 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -5,6 +5,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp new file mode 100644 index 0000000000..bf8d2069b1 --- /dev/null +++ b/components/esm/variant.cpp @@ -0,0 +1,256 @@ +#include "variant.hpp" + +#include +#include + +#include "esmreader.hpp" +#include "variantimp.hpp" + +ESM::Variant::Variant() : mType (VT_None), mData (0) {} + +ESM::Variant::~Variant() +{ + delete mData; +} + +ESM::Variant& ESM::Variant::operator= (const Variant& variant) +{ + if (&variant!=this) + { + VariantDataBase *newData = variant.mData ? variant.mData->clone() : 0; + + delete mData; + + mType = variant.mType; + mData = newData; + } + + return *this; +} + +ESM::Variant::Variant (const Variant& variant) +: mType (variant.mType), mData (variant.mData ? variant.mData->clone() : 0) +{} + +ESM::VarType ESM::Variant::getType() const +{ + return mType; +} + +std::string ESM::Variant::toString() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to string"); + + return mData->getString(); +} + +int ESM::Variant::getInteger() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to integer"); + + return mData->getInteger(); +} + +float ESM::Variant::getFloat() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to float"); + + return mData->getFloat(); +} + +void ESM::Variant::read (ESMReader& esm, Format format) +{ + // type + VarType type = VT_Unknown; + + if (format==Format_Global) + { + std::string typeId = esm.getHNString ("FNAM"); + + if (typeId == "s") + type = VT_Short; + else if (typeId == "l") + type = VT_Long; + else if (typeId == "f") + type = VT_Float; + else + esm.fail ("illegal global variable type " + typeId); + } + else // GMST + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="STRV") + { + type = VT_String; + } + else if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } + + setType (type); + + // data + if (mData) + mData->read (esm, format, mType); +} + +void ESM::Variant::write (ESMWriter& esm, Format format) const +{ + if (mType==VT_Unknown) + { + throw std::runtime_error ("can not serialise variant of unknown type"); + } + else if (mType==VT_None) + { + if (format==Format_Global) + throw std::runtime_error ("can not serialise variant of type none to global format"); + + // nothing to do here for GMST format + } + else + mData->write (esm, format, mType); +} + +void ESM::Variant::write (std::ostream& stream) const +{ + switch (mType) + { + case VT_Unknown: + + stream << "variant unknown"; + break; + + case VT_None: + + stream << "variant none"; + break; + + case VT_Short: + + stream << "variant short: " << mData->getInteger(); + break; + + case VT_Int: + + stream << "variant int: " << mData->getInteger(); + break; + + case VT_Long: + + stream << "variant long: " << mData->getInteger(); + break; + + case VT_Float: + + stream << "variant float: " << mData->getFloat(); + break; + + case VT_String: + + stream << "variant string: \"" << mData->getString() << "\2"; + break; + } +} + +void ESM::Variant::setType (VarType type) +{ + if (type!=mType) + { + VariantDataBase *newData = 0; + + switch (type) + { + case VT_Unknown: + case VT_None: + + break; // no data + + case VT_Short: + case VT_Int: + case VT_Long: + + newData = new VariantIntegerData (mData); + break; + + case VT_Float: + + newData = new VariantFloatData (mData); + break; + + case VT_String: + + newData = new VariantStringData (mData); + break; + } + + delete mData; + mData = newData; + mType = type; + } +} + +void ESM::Variant::setString (const std::string& value) +{ + if (!mData) + throw std::runtime_error ("can not assign string to empty variant"); + + mData->setString (value); +} + +void ESM::Variant::setInteger (int value) +{ + if (!mData) + throw std::runtime_error ("can not assign integer to empty variant"); + + mData->setInteger (value); +} + +void ESM::Variant::setFloat (float value) +{ + if (!mData) + throw std::runtime_error ("can not assign float to empty variant"); + + mData->setFloat (value); +} + +bool ESM::Variant::isEqual (const Variant& value) const +{ + if (mType!=value.mType) + return false; + + if (!mData) + return true; + + assert (value.mData); + + return mData->isEqual (*value.mData); +} + +std::ostream& ESM::operator<< (std::ostream& stream, const Variant& value) +{ + value.write (stream); + return stream; +} + +bool ESM::operator== (const Variant& left, const Variant& right) +{ + return left.isEqual (right); +} + +bool ESM::operator!= (const Variant& left, const Variant& right) +{ + return !(left==right); +} \ No newline at end of file diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp new file mode 100644 index 0000000000..b50bb1d2fe --- /dev/null +++ b/components/esm/variant.hpp @@ -0,0 +1,85 @@ +#ifndef OPENMW_ESM_VARIANT_H +#define OPENMW_ESM_VARIANT_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + enum VarType + { + VT_Unknown, + VT_None, + VT_Short, // stored as a float, kinda + VT_Int, + VT_Long, // stored as a float + VT_Float, + VT_String + }; + + class VariantDataBase; + + class Variant + { + VarType mType; + VariantDataBase *mData; + + public: + + enum Format + { + Format_Global, + Format_Gmst + }; + + Variant(); + + ~Variant(); + + Variant& operator= (const Variant& variant); + + Variant (const Variant& variant); + + VarType getType() const; + + std::string toString() const; + ///< Will throw an exception, if value can not be represented as a string. + + int getInteger() const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + + float getFloat() const; + ///< Will throw an exception, if value can not be represented as a float value. + + void read (ESMReader& esm, Format format); + + void write (ESMWriter& esm, Format format) const; + + void write (std::ostream& stream) const; + ///< Write in text format. + + void setType (VarType type); + + void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + + void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + bool isEqual (const Variant& value) const; + }; + + std::ostream& operator<<(std::ostream& stream, const Variant& value); + + bool operator== (const Variant& left, const Variant& right); + bool operator!= (const Variant& left, const Variant& right); +} + +#endif \ No newline at end of file diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp new file mode 100644 index 0000000000..e99cc50b5a --- /dev/null +++ b/components/esm/variantimp.cpp @@ -0,0 +1,262 @@ + +#include "variantimp.hpp" + +#include + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +ESM::VariantDataBase::~VariantDataBase() {} + +std::string ESM::VariantDataBase::getString (bool default_) const +{ + if (default_) + return ""; + + throw std::runtime_error ("can not convert variant to string"); +} + +int ESM::VariantDataBase::getInteger (bool default_) const +{ + if (default_) + return 0; + + throw std::runtime_error ("can not convert variant to integer"); +} + +float ESM::VariantDataBase::getFloat (bool default_) const +{ + if (default_) + return 0; + + throw std::runtime_error ("can not convert variant to float"); +} + +void ESM::VariantDataBase::setString (const std::string& value) +{ + throw std::runtime_error ("conversion of string to variant not possible"); +} + +void ESM::VariantDataBase::setInteger (int value) +{ + throw std::runtime_error ("conversion of integer to variant not possible"); +} + +void ESM::VariantDataBase::setFloat (float value) +{ + throw std::runtime_error ("conversion of float to variant not possible"); +} + + + +ESM::VariantStringData::VariantStringData (const VariantDataBase *data) +{ + if (data) + mValue = data->getString (true); +} + +ESM::VariantDataBase *ESM::VariantStringData::clone() const +{ + return new VariantStringData (*this); +} + +std::string ESM::VariantStringData::getString (bool default_) const +{ + return mValue; +} + +void ESM::VariantStringData::setString (const std::string& value) +{ + mValue = value; +} + +void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_String) + throw std::logic_error ("not a string type"); + + if (format==Variant::Format_Global) + esm.fail ("global variables of type string not supported"); + + // GMST + mValue = esm.getHString(); +} + +void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_String) + throw std::logic_error ("not a string type"); + + if (format==Variant::Format_Global) + throw std::runtime_error ("global variables of type string not supported"); + + // GMST + esm.writeHNString ("STRV", mValue); +} + +bool ESM::VariantStringData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} + + + +ESM::VariantIntegerData::VariantIntegerData (const VariantDataBase *data) : mValue (0) +{ + if (data) + mValue = data->getInteger (true); +} + +ESM::VariantDataBase *ESM::VariantIntegerData::clone() const +{ + return new VariantIntegerData (*this); +} + +int ESM::VariantIntegerData::getInteger (bool default_) const +{ + return mValue; +} + +float ESM::VariantIntegerData::getFloat (bool default_) const +{ + return mValue; +} + +void ESM::VariantIntegerData::setInteger (int value) +{ + mValue = value; +} + +void ESM::VariantIntegerData::setFloat (float value) +{ + mValue = static_cast (value); +} + +void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_Short && type!=VT_Long && type!=VT_Int) + throw std::logic_error ("not an integer type"); + + if (format==Variant::Format_Global) + { + float value; + esm.getHNT (value, "FLTV"); + + if (type==VT_Short) + { + if (value!=value) + mValue = 0; // nan + else + mValue = static_cast (value); + } + else if (type==VT_Long) + mValue = static_cast (value); + else + esm.fail ("unsupported global variable integer type"); + } + else // GMST + { + if (type==VT_Int) + esm.fail ("unsupported global variable integer type"); + + esm.getHT (mValue); + } +} + +void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_Short && type!=VT_Long && type!=VT_Int) + throw std::logic_error ("not an integer type"); + + if (format==Variant::Format_Global) + { + if (type==VT_Short || type==VT_Long) + { + float value = mValue; + esm.writeHNString ("FNAM", type==VT_Short ? "s" : "l"); + esm.writeHNT ("FLTV", value); + } + else + throw std::runtime_error ("unsupported global variable integer type"); + } + else // GMST + { + if (type==VT_Int) + throw std::runtime_error ("unsupported global variable integer type"); + + esm.writeHNT ("INTV", mValue); + } +} + +bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} + + +ESM::VariantFloatData::VariantFloatData (const VariantDataBase *data) : mValue (0) +{ + if (data) + mValue = data->getFloat (true); +} + +ESM::VariantDataBase *ESM::VariantFloatData::clone() const +{ + return new VariantFloatData (*this); +} + +int ESM::VariantFloatData::getInteger (bool default_) const +{ + return static_cast (mValue); +} + +float ESM::VariantFloatData::getFloat (bool default_) const +{ + return mValue; +} + +void ESM::VariantFloatData::setInteger (int value) +{ + mValue = value; +} + +void ESM::VariantFloatData::setFloat (float value) +{ + mValue = value; +} + +void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_Float) + throw std::logic_error ("not a float type"); + + if (format==Variant::Format_Global) + { + esm.getHNT (mValue, "FLTV"); + } + else // GMST + { + esm.getHT (mValue); + } +} + +void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_Float) + throw std::logic_error ("not a float type"); + + if (format==Variant::Format_Global) + { + esm.writeHNString ("FNAM", "f"); + esm.writeHNT ("FLTV", mValue); + } + else // GMST + { + esm.writeHNT ("INTV", mValue); + } +} + +bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} \ No newline at end of file diff --git a/components/esm/variantimp.hpp b/components/esm/variantimp.hpp new file mode 100644 index 0000000000..1dc20c21f2 --- /dev/null +++ b/components/esm/variantimp.hpp @@ -0,0 +1,179 @@ +#ifndef OPENMW_ESM_VARIANTIMP_H +#define OPENMW_ESM_VARIANTIMP_H + +#include + +#include "variant.hpp" + +namespace ESM +{ + class VariantDataBase + { + public: + + virtual ~VariantDataBase(); + + virtual VariantDataBase *clone() const = 0; + + virtual std::string getString (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a string. + /// + /// \note Numeric values are not converted to strings. + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + /// + /// Default-implementation: throw an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + /// + /// Default-implementation: throw an exception. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + /// + /// Default-implementation: throw an exception. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type) = 0; + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const = 0; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const = 0; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + + }; + + class VariantStringData : public VariantDataBase + { + std::string mValue; + + public: + + VariantStringData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual std::string getString (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a string. + /// + /// \note Numeric values are not converted to strings. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; + + class VariantIntegerData : public VariantDataBase + { + int mValue; + + public: + + VariantIntegerData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; + + class VariantFloatData : public VariantDataBase + { + float mValue; + + public: + + VariantFloatData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; +} + +#endif From a1ac20c6f398ef38ff2797a6ab0ba6ed264c0e2e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Mar 2013 14:32:59 +0100 Subject: [PATCH 0593/1483] changed global variable records to new variant type --- apps/esmtool/record.cpp | 4 +-- apps/opencs/model/doc/document.cpp | 12 ++++--- apps/opencs/model/world/columns.hpp | 4 +-- apps/openmw/mwworld/globals.cpp | 11 +++---- components/esm/loadglob.cpp | 49 ++++------------------------- components/esm/loadglob.hpp | 4 +-- 6 files changed, 22 insertions(+), 62 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a732f19381..9292014176 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -713,9 +713,7 @@ void Record::print() template<> void Record::print() { - // nothing to print (well, nothing that's correct anyway) - std::cout << " Type: " << mData.mType << std::endl; - std::cout << " Value: " << mData.mValue << std::endl; + std::cout << " " << mData.mValue << std::endl; } template<> diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index b361577bec..f6df1f499e 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -154,8 +154,7 @@ void CSMDoc::Document::addOptionalGlobals() { ESM::Global global; global.mId = sGlobals[i]; - global.mType = ESM::VT_Int; - global.mValue = 0; + global.mValue.setType (ESM::VT_Int); addOptionalGlobal (global); } } @@ -192,9 +191,14 @@ void CSMDoc::Document::createBase() for (int i=0; sGlobals[i]; ++i) { ESM::Global record; + record.mId = sGlobals[i]; - record.mValue = i==0 ? 1 : 0; - record.mType = ESM::VT_Float; + + record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Int); + + if (i==0) + record.mValue.setInteger (1); + getData().getGlobals().add (record); } } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2d81a24e90..8855edc464 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -12,13 +12,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mValue; + return record.get().mValue.getFloat(); } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mValue = data.toFloat(); + record2.mValue.setFloat (data.toFloat()); record.setModified (record2); } diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 8742dd8927..9e57910ee0 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -47,27 +47,24 @@ namespace MWWorld char type = ' '; Data value; - switch (iter->mType) + switch (iter->mValue.getType()) { case ESM::VT_Short: type = 's'; - value.mShort = *reinterpret_cast ( - &iter->mValue); + value.mShort = iter->mValue.getInteger(); break; case ESM::VT_Long: type = 'l'; - value.mLong = *reinterpret_cast ( - &iter->mValue); + value.mLong = iter->mValue.getInteger(); break; case ESM::VT_Float: type = 'f'; - value.mFloat = *reinterpret_cast ( - &iter->mValue); + value.mFloat = iter->mValue.getFloat(); break; default: diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 9e20578ce4..0cb6d0a416 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -6,60 +6,23 @@ namespace ESM { -void Global::load(ESMReader &esm) -{ - std::string tmp = esm.getHNString("FNAM"); - if (tmp == "s") - mType = VT_Short; - else if (tmp == "l") - mType = VT_Long; - else if (tmp == "f") - mType = VT_Float; - else - esm.fail("Illegal global variable type " + tmp); - - // Note: Both floats and longs are represented as floats. - esm.getHNT(mValue, "FLTV"); - - if (mType==VT_Short) + void Global::load(ESMReader &esm) { - if (mValue!=mValue) - mValue = 0; // nan - else - mValue = static_cast (mValue); + mValue.read (esm, ESM::Variant::Format_Global); } -} -void Global::save(ESMWriter &esm) -{ - switch(mType) + void Global::save(ESMWriter &esm) { - case VT_Short: - esm.writeHNString("FNAM", "s"); - break; - - case VT_Long: - esm.writeHNString("FNAM", "l"); - break; - - case VT_Float: - esm.writeHNString("FNAM", "f"); - break; - - default: - return; + mValue.write (esm, ESM::Variant::Format_Global); } - esm.writeHNT("FLTV", mValue); -} void Global::blank() { - mValue = 0; - mType = VT_Float; + mValue.setType (ESM::VT_None); } bool operator== (const Global& left, const Global& right) { - return left.mId==right.mId && left.mValue==right.mValue && left.mType==right.mType; + return left.mId==right.mId && left.mValue==right.mValue; } } diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 96d2fcaf42..72e16c0ce5 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -3,7 +3,6 @@ #include -#include "defs.hpp" #include "variant.hpp" namespace ESM @@ -19,8 +18,7 @@ class ESMWriter; struct Global { std::string mId; - float mValue; - VarType mType; + Variant mValue; void load(ESMReader &esm); void save(ESMWriter &esm); From cab5315a8e6ff5c785930787051e14084db5cc20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Mar 2013 16:28:20 +0100 Subject: [PATCH 0594/1483] Disable mipmaps generation --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- files/settings-default.cfg | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 382ec6557e..3f559c9fd4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -100,7 +100,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mFactory->loadAllFiles(); // Set default mipmap level (NB some APIs ignore this) - TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); + // Mipmap generation is currently disabled because it causes issues on Intel/AMD + //TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); // Set default texture filtering options TextureFilterOptions tfo; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6ff7fb4328..69aa208838 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -52,7 +52,8 @@ texture filtering = anisotropic anisotropy = 4 # Number of texture mipmaps to generate -num mipmaps = 5 +# This setting is currently ignored due to mipmap generation problems on Intel/AMD +#num mipmaps = 5 shader mode = From ca707aa65f6d16126cb33f63f6096691af61531a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Mar 2013 16:57:00 +0100 Subject: [PATCH 0595/1483] Transparency should be evaluated per subentity, not per NIF --- apps/openmw/mwrender/activatoranimation.cpp | 19 +++-------- apps/openmw/mwrender/creatureanimation.cpp | 18 ++--------- apps/openmw/mwrender/npcanimation.cpp | 36 ++++----------------- apps/openmw/mwrender/objects.cpp | 30 +++++++---------- 4 files changed, 24 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 0dc16ecb6f..961c070038 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -30,24 +30,13 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) { Ogre::Entity *ent = mEntityList.mEntities[i]; - bool transparent = false; - for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) + for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { - Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + Ogre::SubEntity* subEnt = ent->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } + ent->setVisibilityFlags(RV_Misc); - ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } setAnimationSource(mesh); } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 73bb80547d..22f84ee018 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -31,23 +31,11 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) Ogre::Entity *ent = mEntityList.mEntities[i]; ent->setVisibilityFlags(RV_Actors); - bool transparent = false; - for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) + for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { - Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + Ogre::SubEntity* subEnt = ent->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } - ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } std::vector names; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 33addd284c..a7d5c22afc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -107,23 +107,11 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor if (mVisibilityFlags != 0) base->setVisibilityFlags(mVisibilityFlags); - bool transparent = false; - for(unsigned int j=0;!transparent && j < base->getNumSubEntities();++j) + for(unsigned int j=0; j < base->getNumSubEntities(); ++j) { - Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + Ogre::SubEntity* subEnt = base->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } - base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } std::vector skelnames(1, smodel); @@ -326,23 +314,11 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int if (mVisibilityFlags != 0) parts[i]->setVisibilityFlags(mVisibilityFlags); - bool transparent = false; - for(unsigned int j=0;!transparent && j < parts[i]->getNumSubEntities();++j) + for(unsigned int j=0; j < parts[i]->getNumSubEntities(); ++j) { - Ogre::MaterialPtr mat = parts[i]->getSubEntity(j)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + Ogre::SubEntity* subEnt = parts[i]->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } - parts[i]->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } if(entities.mSkelBase) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 525dcdcc4e..cb1dfa75be 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -129,36 +129,28 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()].merge(bounds); - bool transparent = false; - for(size_t i = 0;!transparent && i < entities.mEntities.size();i++) + bool anyTransparency = false; + for(size_t i = 0;!anyTransparency && i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; - for(unsigned int i=0;!transparent && i < ent->getNumSubEntities(); ++i) + for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i) { - Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent(); } } - if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) + if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || anyTransparency) { for(size_t i = 0;i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; - + for(unsigned int i=0; i < ent->getNumSubEntities(); ++i) + { + Ogre::SubEntity* subEnt = ent->getSubEntity(i); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? 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 @@ -203,7 +195,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool sg->setCastShadows(true); - sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + sg->setRenderQueueGroup(RQG_Main); std::vector::reverse_iterator iter = entities.mEntities.rbegin(); while(iter != entities.mEntities.rend()) From d5c6c221c102699e548256721aa6ac4d06f9dae9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Mar 2013 17:28:01 +0100 Subject: [PATCH 0596/1483] Books/scrolls: Fix the take button incorrectly showing --- apps/openmw/mwgui/inventorywindow.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 40771af166..4a02346445 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -160,11 +160,8 @@ namespace MWGui // the "Take" button should not be visible. // NOTE: the take button is "reset" when the window opens, so we can safely do the following // without screwing up future book windows - if (mDragAndDrop->mDraggedFrom == this) - { - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); - } + mWindowManager.getBookWindow()->setTakeButtonShow(false); + mWindowManager.getScrollWindow()->setTakeButtonShow(false); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); From 9f0bd95ef1122883e1e8e5e9542c9d93ba9ed7f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Mar 2013 17:57:35 +0100 Subject: [PATCH 0597/1483] Added BM trees to transparency overrides --- files/transparency-overrides.cfg | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/files/transparency-overrides.cfg b/files/transparency-overrides.cfg index 299792be17..65f9b477af 100644 --- a/files/transparency-overrides.cfg +++ b/files/transparency-overrides.cfg @@ -572,3 +572,52 @@ [textures\tx_velothi_glyph00.dds] alphaRejectValue = 128 + + + +# Bloodmoon + +[textures\tx_bm_holly_01.dds] + alphaRejectValue = 128 + +[textures\tx_bm_holly_snow_01.dds] + alphaRejectValue = 128 + +[textures\tx_bm_pine_04a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_pine_03a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_pine_02a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_pine_01a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_shrub_02.dds] + alphaRejectValue = 128 + +[textures\tx_bm_shrub_01.dds] + alphaRejectValue = 128 + +[textures\tx_bm_snow_pine_01a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_snow_pine_02a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_snow_pine_03a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_snow_pine_04a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_deadpine_01.dds] + alphaRejectValue = 128 + +[textures\tx_bm_shrub_snow_02.dds] + alphaRejectValue = 128 + +[textures\tx_bm_s_deadpine_01.dds] + alphaRejectValue = 128 From 2f14f26b96cbe5c0cf79c9a35840bcde862a9966 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Mar 2013 10:35:13 -0800 Subject: [PATCH 0598/1483] Use the full unique mesh name for the material instead of the NIF name --- components/nifogre/ogrenifloader.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 44a8e48cd1..6f7afee434 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -993,7 +993,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, + std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop); if(matname.length() > 0) @@ -1001,12 +1001,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, - const Nif::NiTexturingProperty *texprop=NULL, - const Nif::NiMaterialProperty *matprop=NULL, - const Nif::NiAlphaProperty *alphaprop=NULL, - const Nif::NiVertexColorProperty *vertprop=NULL, - const Nif::NiZBufferProperty *zprop=NULL, - const Nif::NiSpecularProperty *specprop=NULL) + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop) { // Scan the property list for material information const Nif::PropertyList &proplist = node->props; @@ -1081,7 +1081,7 @@ public: } const Nif::Node *node = dynamic_cast(nif->getRecord(0)); - findTriShape(mesh, node); + findTriShape(mesh, node, NULL, NULL, NULL, NULL, NULL, NULL); } void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) From fb5213a754cab17c457c649bdb089f96ed519424 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 5 Mar 2013 02:17:28 +0100 Subject: [PATCH 0599/1483] Made the GraphicsPage use a .ui file and added support for custom res --- apps/launcher/graphicspage.cpp | 137 ++++++++++++++++--------------- apps/launcher/graphicspage.hpp | 21 ++--- apps/launcher/ui/graphicspage.ui | 22 +++-- 3 files changed, 92 insertions(+), 88 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 741aacc9df..5905043548 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -30,48 +30,17 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &g , mGraphicsSettings(graphicsSetting) , QWidget(parent) { - QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this); + setupUi(this); - QLabel *rendererLabel = new QLabel(tr("Rendering Subsystem:"), rendererGroup); - mRendererComboBox = new QComboBox(rendererGroup); + // Set the maximum res we can set in windowed mode + QRect res = QApplication::desktop()->screenGeometry(); + customWidthSpinBox->setMaximum(res.width()); + customHeightSpinBox->setMaximum(res.height()); - // Layout for the combobox and label - QGridLayout *renderSystemLayout = new QGridLayout(); - renderSystemLayout->addWidget(rendererLabel, 0, 0, 1, 1); - renderSystemLayout->addWidget(mRendererComboBox, 0, 1, 1, 1); + connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&))); + connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int))); + connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool))); - // Display - QGroupBox *displayGroup = new QGroupBox(tr("Display"), this); - - mVSyncCheckBox = new QCheckBox(tr("Vertical Sync"), displayGroup); - mFullScreenCheckBox = new QCheckBox(tr("Full Screen"), displayGroup); - - QLabel *antiAliasingLabel = new QLabel(tr("Antialiasing:"), displayGroup); - QLabel *resolutionLabel = new QLabel(tr("Resolution:"), displayGroup); - - mResolutionComboBox = new QComboBox(displayGroup); - mAntiAliasingComboBox = new QComboBox(displayGroup); - - QVBoxLayout *rendererGroupLayout = new QVBoxLayout(rendererGroup); - rendererGroupLayout->addLayout(renderSystemLayout); - - QGridLayout *displayGroupLayout = new QGridLayout(displayGroup); - displayGroupLayout->addWidget(mVSyncCheckBox, 0, 0, 1, 1); - displayGroupLayout->addWidget(mFullScreenCheckBox, 1, 0, 1, 1); - displayGroupLayout->addWidget(antiAliasingLabel, 2, 0, 1, 1); - displayGroupLayout->addWidget(mAntiAliasingComboBox, 2, 1, 1, 1); - displayGroupLayout->addWidget(resolutionLabel, 3, 0, 1, 1); - displayGroupLayout->addWidget(mResolutionComboBox, 3, 1, 1, 1); - - // Layout for the whole page - QVBoxLayout *pageLayout = new QVBoxLayout(this); - QSpacerItem *vSpacer1 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding); - - pageLayout->addWidget(rendererGroup); - pageLayout->addWidget(displayGroup); - pageLayout->addItem(vSpacer1); - - connect(mRendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&))); } bool GraphicsPage::setupOgre() @@ -138,7 +107,7 @@ bool GraphicsPage::setupOgre() for (Ogre::RenderSystemList::const_iterator r = renderers.begin(); r != renderers.end(); ++r) { mSelectedRenderSystem = *r; - mRendererComboBox->addItem((*r)->getName().c_str()); + rendererComboBox->addItem((*r)->getName().c_str()); } QString openGLName = QString("OpenGL Rendering Subsystem"); @@ -160,21 +129,21 @@ bool GraphicsPage::setupOgre() } // Now fill the GUI elements - int index = mRendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system"))); + int index = rendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system"))); if ( index != -1) { - mRendererComboBox->setCurrentIndex(index); + rendererComboBox->setCurrentIndex(index); } else { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(direct3DName)); + rendererComboBox->setCurrentIndex(rendererComboBox->findText(direct3DName)); #else - mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(openGLName)); + rendererComboBox->setCurrentIndex(rendererComboBox->findText(openGLName)); #endif } - mAntiAliasingComboBox->clear(); - mResolutionComboBox->clear(); - mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); + antiAliasingComboBox->clear(); + resolutionComboBox->clear(); + antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); + resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); // Load the rest of the values loadSettings(); @@ -184,38 +153,46 @@ bool GraphicsPage::setupOgre() void GraphicsPage::loadSettings() { if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) - mVSyncCheckBox->setCheckState(Qt::Checked); + vSyncCheckBox->setCheckState(Qt::Checked); if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) - mFullScreenCheckBox->setCheckState(Qt::Checked); + fullScreenCheckBox->setCheckState(Qt::Checked); - int aaIndex = mAntiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); + int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); if (aaIndex != -1) - mAntiAliasingComboBox->setCurrentIndex(aaIndex); + antiAliasingComboBox->setCurrentIndex(aaIndex); - QString resolution = mGraphicsSettings.value(QString("Video/resolution x")); - resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); + QString width = mGraphicsSettings.value(QString("Video/resolution x")); + QString height = mGraphicsSettings.value(QString("Video/resolution y")); + QString resolution = width + QString(" x ") + height; - int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); + int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith); - if (resIndex != -1) - mResolutionComboBox->setCurrentIndex(resIndex); + if (resIndex != -1) { + standardRadioButton->toggle(); + resolutionComboBox->setCurrentIndex(resIndex); + } else { + customRadioButton->toggle(); + customWidthSpinBox->setValue(width.toInt()); + customHeightSpinBox->setValue(height.toInt()); + + } } void GraphicsPage::saveSettings() { - mVSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true")) + vSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true")) : mGraphicsSettings.setValue(QString("Video/vsync"), QString("false")); - mFullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) + fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) : mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false")); - mGraphicsSettings.setValue(QString("Video/antialiasing"), mAntiAliasingComboBox->currentText()); - mGraphicsSettings.setValue(QString("Video/render system"), mRendererComboBox->currentText()); + mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); + mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText()); QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); - if (resolutionRe.exactMatch(mResolutionComboBox->currentText().simplified())) { + if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); } @@ -277,6 +254,7 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) // remove extra tokens after the resolution (for example bpp, can be there or not depending on rendersystem) QStringList tokens = qval.split(" ", QString::SkipEmptyParts); assert (tokens.size() >= 3); + QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2); QString aspect = getAspect(tokens.at(0).toInt(),tokens.at(2).toInt()); @@ -304,9 +282,36 @@ void GraphicsPage::rendererChanged(const QString &renderer) { mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); - mAntiAliasingComboBox->clear(); - mResolutionComboBox->clear(); + antiAliasingComboBox->clear(); + resolutionComboBox->clear(); - mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); + antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); + resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); +} + +void GraphicsPage::slotFullScreenChanged(int state) +{ + if (state == Qt::Checked) { + standardRadioButton->toggle(); + customRadioButton->setEnabled(false); + customWidthSpinBox->setEnabled(false); + customHeightSpinBox->setEnabled(false); + } else { + customRadioButton->setEnabled(true); + customWidthSpinBox->setEnabled(true); + customHeightSpinBox->setEnabled(true); + } +} + +void GraphicsPage::slotStandardToggled(bool checked) +{ + if (checked) { + resolutionComboBox->setEnabled(true); + customWidthSpinBox->setEnabled(false); + customHeightSpinBox->setEnabled(false); + } else { + resolutionComboBox->setEnabled(false); + customWidthSpinBox->setEnabled(true); + customHeightSpinBox->setEnabled(true); + } } diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 48b9ff7854..21039af430 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -16,16 +16,13 @@ # include "OgreD3D9Plugin.h" #endif -class QComboBox; -class QCheckBox; -class QStackedWidget; -class QSettings; +#include "ui_graphicspage.h" class GraphicsSettings; namespace Files { struct ConfigurationManager; } -class GraphicsPage : public QWidget +class GraphicsPage : public QWidget, private Ui::GraphicsPage { Q_OBJECT @@ -38,6 +35,10 @@ public: public slots: void rendererChanged(const QString &renderer); +private slots: + void slotFullScreenChanged(int state); + void slotStandardToggled(bool checked); + private: Ogre::Root *mOgre; Ogre::RenderSystem *mSelectedRenderSystem; @@ -50,22 +51,12 @@ private: Ogre::D3D9Plugin* mD3D9Plugin; #endif - QComboBox *mRendererComboBox; - - QStackedWidget *mDisplayStackedWidget; - - QComboBox *mAntiAliasingComboBox; - QComboBox *mResolutionComboBox; - QCheckBox *mVSyncCheckBox; - QCheckBox *mFullScreenCheckBox; - Files::ConfigurationManager &mCfgMgr; GraphicsSettings &mGraphicsSettings; QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); QStringList getAvailableResolutions(Ogre::RenderSystem *renderer); - void createPages(); void loadSettings(); }; diff --git a/apps/launcher/ui/graphicspage.ui b/apps/launcher/ui/graphicspage.ui index e04cd58559..5c330cebd5 100644 --- a/apps/launcher/ui/graphicspage.ui +++ b/apps/launcher/ui/graphicspage.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 300 + 332 + 297
@@ -33,7 +33,7 @@ - GroupBox + Display @@ -73,9 +73,13 @@ - + - + + + 800 + + @@ -85,7 +89,11 @@ - + + + 600 + + @@ -101,7 +109,7 @@ Standard: - + true From 4c9d0563fe4d96f3ca50489b3ea2d4abbf48a44d Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 5 Mar 2013 03:13:39 +0100 Subject: [PATCH 0600/1483] WIP: Implementing the .ui for the DataFilesPage --- apps/launcher/CMakeLists.txt | 13 +- apps/launcher/datafilespage.cpp | 272 +++++++++--------- apps/launcher/datafilespage.hpp | 19 +- apps/launcher/maindialog.cpp | 9 +- components/CMakeLists.txt | 2 +- .../fileorderlist}/utils/comboboxlineedit.cpp | 0 .../fileorderlist}/utils/comboboxlineedit.hpp | 0 .../fileorderlist}/utils/profilescombobox.cpp | 0 .../fileorderlist}/utils/profilescombobox.hpp | 0 9 files changed, 155 insertions(+), 160 deletions(-) rename {apps/launcher => components/fileorderlist}/utils/comboboxlineedit.cpp (100%) rename {apps/launcher => components/fileorderlist}/utils/comboboxlineedit.hpp (100%) rename {apps/launcher => components/fileorderlist}/utils/profilescombobox.cpp (100%) rename {apps/launcher => components/fileorderlist}/utils/profilescombobox.hpp (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 206e94794e..a1c2289456 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -12,8 +12,6 @@ set(LAUNCHER settings/launchersettings.cpp utils/checkablemessagebox.cpp - utils/comboboxlineedit.cpp - utils/profilescombobox.cpp utils/textinputdialog.cpp launcher.rc @@ -33,8 +31,6 @@ set(LAUNCHER_HEADER settings/settingsbase.hpp utils/checkablemessagebox.hpp - utils/comboboxlineedit.hpp - utils/profilescombobox.hpp utils/textinputdialog.hpp ) @@ -49,15 +45,14 @@ set(LAUNCHER_HEADER_MOC model/pluginsproxymodel.hpp utils/checkablemessagebox.hpp - utils/comboboxlineedit.hpp - utils/profilescombobox.hpp utils/textinputdialog.hpp ) set(LAUNCHER_UI - ./ui/graphicspage.ui - ./ui/mainwindow.ui - ./ui/playpage.ui + ui/datafilespage.ui + ui/graphicspage.ui + ui/mainwindow.ui + ui/playpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index dd45c66024..d7dccbab6d 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -10,13 +10,13 @@ #include #include +#include #include "model/pluginsproxymodel.hpp" #include "settings/gamesettings.hpp" #include "settings/launchersettings.hpp" -#include "utils/profilescombobox.hpp" #include "utils/textinputdialog.hpp" using namespace ESM; @@ -40,6 +40,8 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam , mLauncherSettings(launcherSettings) , QWidget(parent) { + setupUi(this); + // Models mDataFilesModel = new DataFilesModel(this); @@ -57,113 +59,117 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mFilterProxyModel->setDynamicSortFilter(true); mFilterProxyModel->setSourceModel(mPluginsProxyModel); - // Filter toolbar - QLabel *filterLabel = new QLabel(tr("&Filter:"), this); - LineEdit *filterLineEdit = new LineEdit(this); - filterLabel->setBuddy(filterLineEdit); - - QToolBar *filterToolBar = new QToolBar(this); - filterToolBar->setMovable(false); - - // Create a container widget and a layout to get the spacer to work - QWidget *filterWidget = new QWidget(this); - QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget); - QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - filterLayout->addItem(hSpacer1); - filterLayout->addWidget(filterLabel); - filterLayout->addWidget(filterLineEdit); - - filterToolBar->addWidget(filterWidget); - QCheckBox checkBox; unsigned int height = checkBox.sizeHint().height() + 4; - mMastersTable = new QTableView(this); - mMastersTable->setModel(mMastersProxyModel); - mMastersTable->setObjectName("MastersTable"); - mMastersTable->setContextMenuPolicy(Qt::CustomContextMenu); - mMastersTable->setSortingEnabled(false); - mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mMastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mMastersTable->setAlternatingRowColors(true); - mMastersTable->horizontalHeader()->setStretchLastSection(true); - mMastersTable->horizontalHeader()->hide(); + mastersTable->setModel(mMastersProxyModel); + mastersTable->setObjectName("MastersTable"); + mastersTable->setContextMenuPolicy(Qt::CustomContextMenu); + mastersTable->setSortingEnabled(false); + mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); + mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); + mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + mastersTable->setAlternatingRowColors(true); + mastersTable->horizontalHeader()->setStretchLastSection(true); + mastersTable->horizontalHeader()->hide(); // Set the row height to the size of the checkboxes - mMastersTable->verticalHeader()->setDefaultSectionSize(height); - mMastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mMastersTable->verticalHeader()->hide(); + mastersTable->verticalHeader()->setDefaultSectionSize(height); + mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + mastersTable->verticalHeader()->hide(); - mPluginsTable = new QTableView(this); - mPluginsTable->setModel(mFilterProxyModel); - mPluginsTable->setObjectName("PluginsTable"); - mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); - mPluginsTable->setSortingEnabled(false); - mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mPluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mPluginsTable->setAlternatingRowColors(true); - mPluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); - mPluginsTable->horizontalHeader()->setStretchLastSection(true); - mPluginsTable->horizontalHeader()->hide(); + pluginsTable->setModel(mFilterProxyModel); + pluginsTable->setObjectName("PluginsTable"); + pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); + pluginsTable->setSortingEnabled(false); + pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); + pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); + pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + pluginsTable->setAlternatingRowColors(true); + pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); + pluginsTable->horizontalHeader()->setStretchLastSection(true); + pluginsTable->horizontalHeader()->hide(); - mPluginsTable->verticalHeader()->setDefaultSectionSize(height); - mPluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + pluginsTable->verticalHeader()->setDefaultSectionSize(height); + pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - // Add both tables to a splitter - mSplitter = new QSplitter(this); - mSplitter->setOrientation(Qt::Horizontal); - mSplitter->setChildrenCollapsible(false); // Don't allow the widgets to be hidden - mSplitter->addWidget(mMastersTable); - mSplitter->addWidget(mPluginsTable); - - // Adjust the default widget widths inside the splitter + // Adjust the tableview widths inside the splitter QList sizeList; sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt(); sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt(); - mSplitter->setSizes(sizeList); + splitter->setSizes(sizeList); - // Bottom part with profile options - QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); +// // Filter toolbar +// QLabel *filterLabel = new QLabel(tr("&Filter:"), this); +// LineEdit *filterLineEdit = new LineEdit(this); +// filterLabel->setBuddy(filterLineEdit); - mProfilesComboBox = new ProfilesComboBox(this); - mProfilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); - mProfilesComboBox->setInsertPolicy(QComboBox::NoInsert); - mProfilesComboBox->setDuplicatesEnabled(false); - mProfilesComboBox->setEditEnabled(false); +// QToolBar *filterToolBar = new QToolBar(this); +// filterToolBar->setMovable(false); - mProfileToolBar = new QToolBar(this); - mProfileToolBar->setMovable(false); - mProfileToolBar->setIconSize(QSize(16, 16)); +// // Create a container widget and a layout to get the spacer to work +// QWidget *filterWidget = new QWidget(this); +// QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget); +// QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - mProfileToolBar->addWidget(profileLabel); - mProfileToolBar->addWidget(mProfilesComboBox); +// filterLayout->addItem(hSpacer1); +// filterLayout->addWidget(filterLabel); +// filterLayout->addWidget(filterLineEdit); - QVBoxLayout *pageLayout = new QVBoxLayout(this); +// filterToolBar->addWidget(filterWidget); - pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(mSplitter); - pageLayout->addWidget(mProfileToolBar); + + +// // Add both tables to a splitter +// mSplitter = new QSplitter(this); +// mSplitter->setOrientation(Qt::Horizontal); +// mSplitter->setChildrenCollapsible(false); // Don't allow the widgets to be hidden +// mSplitter->addWidget(mastersTable); +// mSplitter->addWidget(pluginsTable); + + + +// + +// // Bottom part with profile options +// QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); + +// profilesComboBox = new ProfilesComboBox(this); +// profilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); +// profilesComboBox->setInsertPolicy(QComboBox::NoInsert); +// profilesComboBox->setDuplicatesEnabled(false); +// profilesComboBox->setEditEnabled(false); + +// mProfileToolBar = new QToolBar(this); +// mProfileToolBar->setMovable(false); +// mProfileToolBar->setIconSize(QSize(16, 16)); + +// mProfileToolBar->addWidget(profileLabel); +// mProfileToolBar->addWidget(profilesComboBox); + +// QVBoxLayout *pageLayout = new QVBoxLayout(this); + +// pageLayout->addWidget(filterToolBar); +// pageLayout->addWidget(mSplitter); +// pageLayout->addWidget(mProfileToolBar); // Create a dialog for the new profile name input mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); - connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - connect(mMastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(pluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(mastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - connect(mSplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); + connect(splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); createActions(); setupDataFiles(); @@ -188,9 +194,9 @@ void DataFilesPage::createActions() connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); // Add the newly created actions to the toolbar - mProfileToolBar->addSeparator(); - mProfileToolBar->addAction(mNewProfileAction); - mProfileToolBar->addAction(mDeleteProfileAction); +// mProfileToolBar->addSeparator(); +// mProfileToolBar->addAction(mNewProfileAction); +// mProfileToolBar->addAction(mDeleteProfileAction); // Context menu actions mCheckAction = new QAction(tr("Check Selection"), this); @@ -226,25 +232,25 @@ void DataFilesPage::setupDataFiles() QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); if (!profiles.isEmpty()) - mProfilesComboBox->addItems(profiles); + profilesComboBox->addItems(profiles); // Add the current profile if empty - if (mProfilesComboBox->findText(profile) == -1) - mProfilesComboBox->addItem(profile); + if (profilesComboBox->findText(profile) == -1) + profilesComboBox->addItem(profile); - if (mProfilesComboBox->findText(QString("Default")) == -1) - mProfilesComboBox->addItem(QString("Default")); + if (profilesComboBox->findText(QString("Default")) == -1) + profilesComboBox->addItem(QString("Default")); if (profile.isEmpty() || profile == QLatin1String("Default")) { - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(QString("Default"))); + profilesComboBox->setCurrentIndex(profilesComboBox->findText(QString("Default"))); } else { - mProfilesComboBox->setEditEnabled(true); - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); + profilesComboBox->setEditEnabled(true); + profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile)); } // We do this here to prevent deletion of profiles when initializing the combobox - connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); - connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); + connect(profilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); + connect(profilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); loadSettings(); @@ -283,7 +289,7 @@ void DataFilesPage::saveSettings() QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); if (profile.isEmpty()) { - profile = mProfilesComboBox->currentText(); + profile = profilesComboBox->currentText(); mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile); } @@ -313,8 +319,8 @@ void DataFilesPage::newProfile() { if (mNewProfileDialog->exec() == QDialog::Accepted) { QString profile = mNewProfileDialog->lineEdit()->text(); - mProfilesComboBox->addItem(profile); - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); + profilesComboBox->addItem(profile); + profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile)); } } @@ -326,7 +332,7 @@ void DataFilesPage::updateOkButton(const QString &text) return; } - (mProfilesComboBox->findText(text) == -1) + (profilesComboBox->findText(text) == -1) ? mNewProfileDialog->setOkButtonEnabled(true) : mNewProfileDialog->setOkButtonEnabled(false); } @@ -335,7 +341,7 @@ void DataFilesPage::updateSplitter() { // Sigh, update the saved splitter size in settings only when moved // Since getting mSplitter->sizes() if page is hidden returns invalid values - QList sizes = mSplitter->sizes(); + QList sizes = splitter->sizes(); mLauncherSettings.setValue(QString("General/MastersTable/width"), QString::number(sizes.at(0))); mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1))); @@ -344,28 +350,28 @@ void DataFilesPage::updateSplitter() void DataFilesPage::updateViews() { // Ensure the columns are hidden because sort() re-enables them - mMastersTable->setColumnHidden(1, true); - mMastersTable->setColumnHidden(2, true); - mMastersTable->setColumnHidden(3, true); - mMastersTable->setColumnHidden(4, true); - mMastersTable->setColumnHidden(5, true); - mMastersTable->setColumnHidden(6, true); - mMastersTable->setColumnHidden(7, true); - mMastersTable->setColumnHidden(8, true); + mastersTable->setColumnHidden(1, true); + mastersTable->setColumnHidden(2, true); + mastersTable->setColumnHidden(3, true); + mastersTable->setColumnHidden(4, true); + mastersTable->setColumnHidden(5, true); + mastersTable->setColumnHidden(6, true); + mastersTable->setColumnHidden(7, true); + mastersTable->setColumnHidden(8, true); - mPluginsTable->setColumnHidden(1, true); - mPluginsTable->setColumnHidden(2, true); - mPluginsTable->setColumnHidden(3, true); - mPluginsTable->setColumnHidden(4, true); - mPluginsTable->setColumnHidden(5, true); - mPluginsTable->setColumnHidden(6, true); - mPluginsTable->setColumnHidden(7, true); - mPluginsTable->setColumnHidden(8, true); + pluginsTable->setColumnHidden(1, true); + pluginsTable->setColumnHidden(2, true); + pluginsTable->setColumnHidden(3, true); + pluginsTable->setColumnHidden(4, true); + pluginsTable->setColumnHidden(5, true); + pluginsTable->setColumnHidden(6, true); + pluginsTable->setColumnHidden(7, true); + pluginsTable->setColumnHidden(8, true); } void DataFilesPage::deleteProfile() { - QString profile = mProfilesComboBox->currentText(); + QString profile = profilesComboBox->currentText(); if (profile.isEmpty()) return; @@ -386,26 +392,26 @@ void DataFilesPage::deleteProfile() mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); + profilesComboBox->removeItem(profilesComboBox->findText(profile)); } } void DataFilesPage::check() { - if (mPluginsTable->hasFocus()) + if (pluginsTable->hasFocus()) setPluginsCheckstates(Qt::Checked); - if (mMastersTable->hasFocus()) + if (mastersTable->hasFocus()) setMastersCheckstates(Qt::Checked); } void DataFilesPage::uncheck() { - if (mPluginsTable->hasFocus()) + if (pluginsTable->hasFocus()) setPluginsCheckstates(Qt::Unchecked); - if (mMastersTable->hasFocus()) + if (mastersTable->hasFocus()) setMastersCheckstates(Qt::Unchecked); } @@ -414,16 +420,16 @@ void DataFilesPage::refresh() // mDataFilesModel->sort(0); // Refresh the plugins table - mPluginsTable->scrollToTop(); + pluginsTable->scrollToTop(); } void DataFilesPage::setMastersCheckstates(Qt::CheckState state) { - if (!mMastersTable->selectionModel()->hasSelection()) { + if (!mastersTable->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = mMastersTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes(); foreach (const QModelIndex &index, indexes) { @@ -441,11 +447,11 @@ void DataFilesPage::setMastersCheckstates(Qt::CheckState state) void DataFilesPage::setPluginsCheckstates(Qt::CheckState state) { - if (!mPluginsTable->selectionModel()->hasSelection()) { + if (!pluginsTable->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes(); foreach (const QModelIndex &index, indexes) { @@ -509,16 +515,16 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre // Prevent the deletion of the default profile if (current == QLatin1String("Default")) { mDeleteProfileAction->setEnabled(false); - mProfilesComboBox->setEditEnabled(false); + profilesComboBox->setEditEnabled(false); } else { mDeleteProfileAction->setEnabled(true); - mProfilesComboBox->setEditEnabled(true); + profilesComboBox->setEditEnabled(true); } if (previous.isEmpty()) return; - if (mProfilesComboBox->findText(previous) == -1) + if (profilesComboBox->findText(previous) == -1) return; // Profile was deleted // Store the previous profile @@ -543,7 +549,7 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre mLauncherSettings.remove(QString("Profiles/") + previous + QString("/plugin")); // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); + profilesComboBox->removeItem(profilesComboBox->findText(previous)); loadSettings(); @@ -558,11 +564,11 @@ void DataFilesPage::showContextMenu(const QPoint &point) return; if (object->objectName() == QLatin1String("PluginsTable")) { - if (!mPluginsTable->selectionModel()->hasSelection()) + if (!pluginsTable->selectionModel()->hasSelection()) return; - QPoint globalPos = mPluginsTable->mapToGlobal(point); - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QPoint globalPos = pluginsTable->mapToGlobal(point); + QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes(); // Show the check/uncheck actions depending on the state of the selected items mUncheckAction->setEnabled(false); @@ -589,11 +595,11 @@ void DataFilesPage::showContextMenu(const QPoint &point) } if (object->objectName() == QLatin1String("MastersTable")) { - if (!mMastersTable->selectionModel()->hasSelection()) + if (!mastersTable->selectionModel()->hasSelection()) return; - QPoint globalPos = mMastersTable->mapToGlobal(point); - QModelIndexList indexes = mMastersTable->selectionModel()->selectedIndexes(); + QPoint globalPos = mastersTable->mapToGlobal(point); + QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes(); // Show the check/uncheck actions depending on the state of the selected items mUncheckAction->setEnabled(false); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index dd69d7489c..e98b09aef7 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -4,33 +4,28 @@ #include #include -class QTableView; +#include "ui_datafilespage.h" + class QSortFilterProxyModel; class QAction; -class QToolBar; -class QSplitter; class QMenu; -class ProfilesComboBox; class DataFilesModel; class TextInputDialog; -class ProfilesComboBox; class GameSettings; class LauncherSettings; class PluginsProxyModel; namespace Files { struct ConfigurationManager; } -class DataFilesPage : public QWidget +class DataFilesPage : public QWidget, private Ui::DataFilesPage { Q_OBJECT public: DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0); - ProfilesComboBox *mProfilesComboBox; - void writeConfig(QString profile = QString()); void saveSettings(); @@ -60,13 +55,13 @@ private: QSortFilterProxyModel *mFilterProxyModel; - QTableView *mMastersTable; - QTableView *mPluginsTable; +// QTableView *mMastersTable; +// QTableView *mPluginsTable; - QToolBar *mProfileToolBar; +// QToolBar *mProfileToolBar; QMenu *mContextMenu; - QSplitter *mSplitter; +// QSplitter *mSplitter; QAction *mNewProfileAction; QAction *mDeleteProfileAction; diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 5621b75c02..cab763b105 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -3,7 +3,6 @@ #include #include "utils/checkablemessagebox.hpp" -#include "utils/profilescombobox.hpp" #include "playpage.hpp" #include "graphicspage.hpp" @@ -94,8 +93,8 @@ void MainDialog::createPages() mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage - mPlayPage->setProfilesComboBoxModel(mDataFilesPage->mProfilesComboBox->model()); - mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); +// mPlayPage->setProfilesComboBoxModel(mDataFilesPage->mProfilesComboBox->model()); +// mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget pagesWidget->addWidget(mPlayPage); @@ -107,8 +106,8 @@ void MainDialog::createPages() connect(mPlayPage, SIGNAL(playButtonClicked()), this, SLOT(play())); - connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); - connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); +// connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); +// connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00342e2ac8..7c52ab12cc 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -71,7 +71,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui) if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (fileorderlist datafileslist model/modelitem model/datafilesmodel model/esm/esmfile - utils/filedialog utils/lineedit utils/naturalsort + utils/profilescombobox utils/comboboxlineedit utils/lineedit utils/naturalsort ) include(${QT_USE_FILE}) diff --git a/apps/launcher/utils/comboboxlineedit.cpp b/components/fileorderlist/utils/comboboxlineedit.cpp similarity index 100% rename from apps/launcher/utils/comboboxlineedit.cpp rename to components/fileorderlist/utils/comboboxlineedit.cpp diff --git a/apps/launcher/utils/comboboxlineedit.hpp b/components/fileorderlist/utils/comboboxlineedit.hpp similarity index 100% rename from apps/launcher/utils/comboboxlineedit.hpp rename to components/fileorderlist/utils/comboboxlineedit.hpp diff --git a/apps/launcher/utils/profilescombobox.cpp b/components/fileorderlist/utils/profilescombobox.cpp similarity index 100% rename from apps/launcher/utils/profilescombobox.cpp rename to components/fileorderlist/utils/profilescombobox.cpp diff --git a/apps/launcher/utils/profilescombobox.hpp b/components/fileorderlist/utils/profilescombobox.hpp similarity index 100% rename from apps/launcher/utils/profilescombobox.hpp rename to components/fileorderlist/utils/profilescombobox.hpp From 75cf009101828d8f83c98eb0915bede65c1c54dd Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 5 Mar 2013 03:47:57 +0100 Subject: [PATCH 0601/1483] Finished implementing the .ui file for the DataFilesPage --- apps/launcher/datafilespage.cpp | 32 ++++++++++++++++++++++++++------ apps/launcher/datafilespage.hpp | 12 +++++++++++- apps/launcher/maindialog.cpp | 8 ++++---- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index d7dccbab6d..069cdd9ac9 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -157,6 +157,8 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam // Create a dialog for the new profile name input mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int))); + connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); @@ -182,7 +184,7 @@ void DataFilesPage::createActions() refreshAction->setShortcut(QKeySequence(tr("F5"))); connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); - // Profile actions + // We can't create actions inside the .ui file mNewProfileAction = new QAction(QIcon::fromTheme("document-new"), tr("&New Profile"), this); mNewProfileAction->setToolTip(tr("New Profile")); mNewProfileAction->setShortcut(QKeySequence(tr("Ctrl+N"))); @@ -190,13 +192,11 @@ void DataFilesPage::createActions() mDeleteProfileAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete Profile"), this); mDeleteProfileAction->setToolTip(tr("Delete Profile")); - mDeleteProfileAction->setShortcut(QKeySequence(tr("Delete"))); connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); - // Add the newly created actions to the toolbar -// mProfileToolBar->addSeparator(); -// mProfileToolBar->addAction(mNewProfileAction); -// mProfileToolBar->addAction(mDeleteProfileAction); + // Add the newly created actions to the toolbuttons + newProfileButton->setDefaultAction(mNewProfileAction); + deleteProfileButton->setDefaultAction(mDeleteProfileAction); // Context menu actions mCheckAction = new QAction(tr("Check Selection"), this); @@ -369,6 +369,26 @@ void DataFilesPage::updateViews() pluginsTable->setColumnHidden(8, true); } +void DataFilesPage::setProfilesComboBoxIndex(int index) +{ + profilesComboBox->setCurrentIndex(index); +} + +void DataFilesPage::slotCurrentIndexChanged(int index) +{ + emit profileChanged(index); +} + +QAbstractItemModel* DataFilesPage::profilesComboBoxModel() +{ + return profilesComboBox->model(); +} + +int DataFilesPage::profilesComboBoxIndex() +{ + return profilesComboBox->currentIndex(); +} + void DataFilesPage::deleteProfile() { QString profile = profilesComboBox->currentText(); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index e98b09aef7..301abf59bf 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -7,11 +7,11 @@ #include "ui_datafilespage.h" class QSortFilterProxyModel; +class QAbstractItemModel; class QAction; class QMenu; class DataFilesModel; - class TextInputDialog; class GameSettings; class LauncherSettings; @@ -26,12 +26,19 @@ class DataFilesPage : public QWidget, private Ui::DataFilesPage public: DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0); + QAbstractItemModel* profilesComboBoxModel(); + int profilesComboBoxIndex(); + void writeConfig(QString profile = QString()); void saveSettings(); +signals: + void profileChanged(int index); public slots: void setCheckState(QModelIndex index); + void setProfilesComboBoxIndex(int index); + void filterChanged(const QString filter); void showContextMenu(const QPoint &point); void profileChanged(const QString &previous, const QString ¤t); @@ -47,6 +54,9 @@ public slots: void uncheck(); void refresh(); +private slots: + void slotCurrentIndexChanged(int index); + private: DataFilesModel *mDataFilesModel; diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index cab763b105..6a3965cc91 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -93,8 +93,8 @@ void MainDialog::createPages() mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage -// mPlayPage->setProfilesComboBoxModel(mDataFilesPage->mProfilesComboBox->model()); -// mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); + mPlayPage->setProfilesComboBoxModel(mDataFilesPage->profilesComboBoxModel()); + mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->profilesComboBoxIndex()); // Add the pages to the stacked widget pagesWidget->addWidget(mPlayPage); @@ -106,8 +106,8 @@ void MainDialog::createPages() connect(mPlayPage, SIGNAL(playButtonClicked()), this, SLOT(play())); -// connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); -// connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); + connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage, SLOT(setProfilesComboBoxIndex(int))); + connect(mDataFilesPage, SIGNAL(profileChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); } From 770d8af931ea7ad75c3a978761eb36fcd4e1e37c Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 5 Mar 2013 03:57:27 +0100 Subject: [PATCH 0602/1483] Forgot to add the DataFilesPage .ui --- apps/launcher/ui/datafilespage.ui | 125 ++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 apps/launcher/ui/datafilespage.ui diff --git a/apps/launcher/ui/datafilespage.ui b/apps/launcher/ui/datafilespage.ui new file mode 100644 index 0000000000..91b5475e67 --- /dev/null +++ b/apps/launcher/ui/datafilespage.ui @@ -0,0 +1,125 @@ + + + DataFilesPage + + + + 0 + 0 + 520 + 256 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Filter: + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + false + + + + + + + + + + + Current Profile: + + + + + + + + 0 + 0 + + + + + + + + New Profile + + + &New Profile + + + true + + + + + + + Delete Profile + + + Delete Profile + + + Ctrl+D + + + true + + + + + + + + + + LineEdit + QLineEdit +

components/fileorderlist/utils/lineedit.hpp
+ + + ProfilesComboBox + QComboBox +
components/fileorderlist/utils/profilescombobox.hpp
+
+ + + + From ce49ad54a1ef73a557ef0a6d32362d21718ed2e0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:02:05 +0100 Subject: [PATCH 0603/1483] some cleanup and fixing --- components/esm/loadglob.cpp | 8 ++------ components/esm/variant.cpp | 37 ++++++++++++++++++++++--------------- components/esm/variant.hpp | 2 +- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 0cb6d0a416..ccb519acd4 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -1,17 +1,13 @@ #include "loadglob.hpp" -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { - - void Global::load(ESMReader &esm) + void Global::load (ESMReader &esm) { mValue.read (esm, ESM::Variant::Format_Global); } - void Global::save(ESMWriter &esm) + void Global::save (ESMWriter &esm) { mValue.write (esm, ESM::Variant::Format_Global); } diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index bf8d2069b1..98786c20e3 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -37,7 +37,7 @@ ESM::VarType ESM::Variant::getType() const return mType; } -std::string ESM::Variant::toString() const +std::string ESM::Variant::getString() const { if (!mData) throw std::runtime_error ("can not convert empty variant to string"); @@ -81,23 +81,30 @@ void ESM::Variant::read (ESMReader& esm, Format format) } else // GMST { - esm.getSubName(); - NAME name = esm.retSubName(); - - if (name=="STRV") + if (!esm.hasMoreSubs()) { - type = VT_String; - } - else if (name=="INTV") - { - type = VT_Int; - } - else if (name=="FLTV") - { - type = VT_Float; + type = VT_None; } else - esm.fail ("invalid subrecord: " + name.toString()); + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="STRV") + { + type = VT_String; + } + else if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } } setType (type); diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index b50bb1d2fe..b78d647a82 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -45,7 +45,7 @@ namespace ESM VarType getType() const; - std::string toString() const; + std::string getString() const; ///< Will throw an exception, if value can not be represented as a string. int getInteger() const; From ba4907fbaf7ed8d1dee768569b912bf7ee7641cf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:02:27 +0100 Subject: [PATCH 0604/1483] use new Variant type for GMSTs --- apps/esmtool/record.cpp | 18 +----- apps/opencs/model/doc/document.cpp | 10 ++- apps/opencs/model/world/columns.hpp | 31 ++++++--- apps/opencs/model/world/data.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 11 ++-- apps/openmw/mwworld/worldimp.cpp | 14 ++-- components/esm/loadgmst.cpp | 89 ++++---------------------- components/esm/loadgmst.hpp | 10 ++- 8 files changed, 55 insertions(+), 129 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 9292014176..e4de63dd47 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -719,23 +719,7 @@ void Record::print() template<> void Record::print() { - std::cout << " Value: "; - switch (mData.mType) { - case ESM::VT_String: - std::cout << "'" << mData.mStr << "' (std::string)"; - break; - - case ESM::VT_Float: - std::cout << mData.mF << " (float)"; - break; - - case ESM::VT_Int: - std::cout << mData.mI << " (int)"; - break; - - default: - std::cout << "unknown type"; - } + std::cout << " " << mData.mValue << std::endl; } template<> diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index f6df1f499e..6a76b0b6ca 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -116,8 +116,7 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sFloats[i]; - gmst.mF = 0; - gmst.mType = ESM::VT_Float; + gmst.mValue.setType (ESM::VT_Float); addOptionalGmst (gmst); } @@ -125,8 +124,7 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sIntegers[i]; - gmst.mI = 0; - gmst.mType = ESM::VT_Long; + gmst.mValue.setType (ESM::VT_Int); addOptionalGmst (gmst); } @@ -134,8 +132,8 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sStrings[i]; - gmst.mStr = ""; - gmst.mType = ESM::VT_String; + gmst.mValue.setType (ESM::VT_String); + gmst.mValue.setString (""); addOptionalGmst (gmst); } } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 8855edc464..270987ec14 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -100,13 +100,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return static_cast (record.get().mType); + return static_cast (record.get().mValue.getType()); } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mType = static_cast (data.toInt()); + record2.mValue.setType (static_cast (data.toInt())); record.setModified (record2); } @@ -123,11 +123,11 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - switch (record.get().mType) + switch (record.get().mValue.getType()) { - case ESM::VT_String: return record.get().mStr.c_str(); break; - case ESM::VT_Int: return record.get().mI; break; - case ESM::VT_Float: return record.get().mF; break; + case ESM::VT_String: return record.get().mValue.getString().c_str(); break; + case ESM::VT_Int: return record.get().mValue.getInteger(); break; + case ESM::VT_Float: return record.get().mValue.getFloat(); break; default: return QVariant(); } @@ -137,11 +137,22 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - switch (record2.mType) + switch (record2.mValue.getType()) { - case ESM::VT_String: record2.mStr = data.toString().toUtf8().constData(); break; - case ESM::VT_Int: record2.mI = data.toInt(); break; - case ESM::VT_Float: record2.mF = data.toFloat(); break; + case ESM::VT_String: + + record2.mValue.setString (data.toString().toUtf8().constData()); + break; + + case ESM::VT_Int: + + record2.mValue.setInteger (data.toInt()); + break; + + case ESM::VT_Float: + + record2.mValue.setFloat (data.toFloat()); + break; default: break; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c59763f512..d4704b0c64 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "idtable.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1dc11f2c44..efdb86400e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -569,7 +569,7 @@ void WindowManager::messageBox (const std::string& message, const std::vectorcreateMessageBox(message); } - + else { mMessageBoxManager->createInteractiveMessageBox(message, buttons); @@ -592,8 +592,9 @@ std::string WindowManager::getGameSettingString(const std::string &id, const std const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().search(id); - if (setting && setting->mType == ESM::VT_String) - return setting->getString(); + if (setting && setting->mValue.getType()==ESM::VT_String) + return setting->mValue.getString(); + return default_; } @@ -774,8 +775,8 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().find(tag); - if (setting && setting->mType == ESM::VT_String) - _result = setting->getString(); + if (setting && setting->mValue.getType()==ESM::VT_String) + _result = setting->mValue.getString(); else _result = tag; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 90f26096e7..1de0559d91 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -198,7 +198,7 @@ namespace MWWorld 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"; // This parses the ESM file @@ -210,11 +210,11 @@ namespace MWWorld mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } - + 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 @@ -226,7 +226,7 @@ namespace MWWorld mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } - + mStore.setUp(); mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); @@ -363,10 +363,8 @@ namespace MWWorld const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().search("sDefaultCellname"); - if (setting && setting->mType == ESM::VT_String) - name = setting->getString(); - else - name = "Wilderness"; + if (setting && setting->mValue.getType()==ESM::VT_String) + name = setting->mValue.getString(); } } diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index e9852ec076..fe1cc1b047 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -1,104 +1,39 @@ #include "loadgmst.hpp" -#include - -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { - -void GameSetting::load(ESMReader &esm) -{ - assert(mId != ""); - - // We are apparently allowed to be empty - if (!esm.hasMoreSubs()) + void GameSetting::load (ESMReader &esm) { - mType = VT_None; - return; + mValue.read (esm, ESM::Variant::Format_Gmst); } - // Load some data - esm.getSubName(); - NAME n = esm.retSubName(); - if (n == "STRV") + void GameSetting::save (ESMWriter &esm) { - mStr = esm.getHString(); - mType = VT_String; + mValue.write (esm, ESM::Variant::Format_Gmst); } - else if (n == "INTV") - { - esm.getHT(mI); - mType = VT_Int; - } - else if (n == "FLTV") - { - esm.getHT(mF); - mType = VT_Float; - } - else - esm.fail("Unwanted subrecord type"); -} -void GameSetting::save(ESMWriter &esm) -{ - switch(mType) + int GameSetting::getInt() const { - case VT_String: esm.writeHNString("STRV", mStr); break; - case VT_Int: esm.writeHNT("INTV", mI); break; - case VT_Float: esm.writeHNT("FLTV", mF); break; - default: break; + return mValue.getInteger(); } -} -int GameSetting::getInt() const -{ - switch (mType) + float GameSetting::getFloat() const { - case VT_Float: return static_cast (mF); - case VT_Int: return mI; - default: throw std::runtime_error ("GMST " + mId + " is not of a numeric type"); + return mValue.getFloat(); } -} -float GameSetting::getFloat() const -{ - switch (mType) + std::string GameSetting::getString() const { - case VT_Float: return mF; - case VT_Int: return mI; - default: throw std::runtime_error ("GMST " + mId + " is not of a numeric type"); + return mValue.getString(); } -} - -std::string GameSetting::getString() const -{ - if (mType==VT_String) - return mStr; - - throw std::runtime_error ("GMST " + mId + " is not a string"); -} void GameSetting::blank() { - mStr.clear(); - mI = 0; - mF = 0; - mType = VT_Float; + mValue.setType (ESM::VT_None); } bool operator== (const GameSetting& left, const GameSetting& right) { - if (left.mType!=right.mType) - return false; - - switch (left.mType) - { - case VT_Float: return left.mF==right.mF; - case VT_Int: return left.mI==right.mI; - case VT_String: return left.mStr==right.mStr; - default: return false; - } + return left.mValue==right.mValue; } } diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 12f212081c..a6e0c2ecbe 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -3,7 +3,6 @@ #include -#include "defs.hpp" #include "variant.hpp" namespace ESM @@ -20,14 +19,13 @@ class ESMWriter; struct GameSetting { std::string mId; - // One of these is used depending on the variable type - std::string mStr; - int mI; - float mF; - VarType mType; + + Variant mValue; void load(ESMReader &esm); + /// \todo remove the get* functions (redundant, since mValue as equivalent functions now). + int getInt() const; ///< Throws an exception if GMST is not of type int or float. From 1b19ab6028929cc6384afaf8c634cd84abeb2817 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:15:03 +0100 Subject: [PATCH 0605/1483] fixed gmst integers --- components/esm/variantimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index e99cc50b5a..1b8cf4f875 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -156,8 +156,8 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT } else // GMST { - if (type==VT_Int) - esm.fail ("unsupported global variable integer type"); + if (type!=VT_Int) + esm.fail ("unsupported gmst variable integer type"); esm.getHT (mValue); } From 1489570b097bc31103fa1e03ec49ba2081a61a6c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 09:40:41 +0100 Subject: [PATCH 0606/1483] change variant in info record to new type --- apps/esmtool/record.cpp | 9 ++--- apps/openmw/mwdialogue/selectwrapper.cpp | 9 +++-- components/esm/loadinfo.cpp | 25 ++----------- components/esm/loadinfo.hpp | 46 ++---------------------- components/esm/variant.cpp | 21 ++++++++++- components/esm/variant.hpp | 3 +- components/esm/variantimp.cpp | 32 +++++++++++++---- 7 files changed, 59 insertions(+), 86 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e4de63dd47..38fddd6b92 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -112,14 +112,11 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case '5': oper_str = ">="; break; } - std::string value_str = "??"; - if (ss.mType == ESM::VT_Int) - value_str = str(boost::format("%d") % ss.mI); - else if (ss.mType == ESM::VT_Float) - value_str = str(boost::format("%f") % ss.mF); + std::ostringstream stream; + stream << ss.mValue; std::string result = str(boost::format("%-12s %-32s %2s %s") - % type_str % func_str % oper_str % value_str); + % type_str % func_str % oper_str % stream.str()); return result; } diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 9cc528a118..9d705f6bec 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -31,14 +31,13 @@ namespace template bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1) { - if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || - select.mType==ESM::VT_Long) + if (select.mValue.getType()==ESM::VT_Int) { - return selectCompareImp (select.mSelectRule[4], value1, select.mI); + return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getInteger()); } - else if (select.mType==ESM::VT_Float) + else if (select.mValue.getType()==ESM::VT_Float) { - return selectCompareImp (select.mSelectRule[4], value1, select.mF); + return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getFloat()); } else throw std::runtime_error ( diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index f237cf7808..90f8fcf35b 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -84,22 +84,8 @@ void DialInfo::load(ESMReader &esm) SelectStruct ss; ss.mSelectRule = esm.getHString(); - esm.isEmptyOrGetName(); - if (subName.val == REC_INTV) - { - ss.mType = VT_Int; - esm.getHT(ss.mI); - } - else if (subName.val == REC_FLTV) - { - ss.mType = VT_Float; - esm.getHT(ss.mF); - } - else - esm.fail( - "INFO.SCVR must precede INTV or FLTV, not " - + subName.toString()); + ss.mValue.read (esm, Variant::Format_Info); mSelects.push_back(ss); @@ -152,16 +138,11 @@ void DialInfo::save(ESMWriter &esm) for (std::vector::iterator it = mSelects.begin(); it != mSelects.end(); ++it) { esm.writeHNString("SCVR", it->mSelectRule); - switch(it->mType) - { - case VT_Int: esm.writeHNT("INTV", it->mI); break; - case VT_Float: esm.writeHNT("FLTV", it->mF); break; - default: break; - } + it->mValue.write (esm, Variant::Format_Info); } esm.writeHNOString("BNAM", mResultScript); - + switch(mQuestStatus) { case QS_Name: esm.writeHNT("QSTN",'\1'); break; diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index ca08c3b55b..2361ed9eb5 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -13,8 +13,6 @@ namespace ESM class ESMReader; class ESMWriter; -// NOT DONE - /* * Dialogue information. A series of these follow after DIAL records, * and form a linked list of dialogue items. @@ -44,9 +42,7 @@ struct DialInfo struct SelectStruct { std::string mSelectRule; // This has a complicated format - float mF; // Only one of 'f' or 'i' is used - int mI; - VarType mType; + Variant mValue; }; // Journal quest indices (introduced with the quest system in Tribunal) @@ -94,8 +90,7 @@ struct DialInfo REC_SNAM = 0x4d414e53, REC_NAME = 0x454d414e, REC_SCVR = 0x52564353, - REC_INTV = 0x56544e49, - REC_FLTV = 0x56544c46, + REC_BNAM = 0x4d414e42, REC_QSTN = 0x4e545351, REC_QSTF = 0x46545351, @@ -107,42 +102,5 @@ struct DialInfo void save(ESMWriter &esm); }; -/* - Some old and unused D code and comments, that might be useful later: - -------- - - // We only need to put each item in ONE list. For if your NPC - // matches this response, then it must match ALL criteria, thus it - // will have to look up itself in all the lists. I think the order - // is well optimized in making the lists as small as possible. - if(this.actor.index != -1) actorDial[this.actor][parent]++; - else if(cell != "") cellDial[cell][parent]++; - else if(this.Class != -1) classDial[this.Class][parent]++; - else if(this.npcFaction != -1) - factionDial[this.npcFaction][parent]++; - else if(this.race != -1) raceDial[this.race][parent]++; - else allDial[parent]++; // Lists dialogues that might - // apply to all npcs. - */ - -// List of dialogue topics (and greetings, voices, etc.) that -// reference other objects. Eg. raceDial is indexed by the indices of -// all races referenced. The value of raceDial is a new AA, which is -// basically used as a map (the int value is just a count and isn't -// used for anything important.) The indices (or elements of the map) -// are the dialogues that reference the given race. I use an AA -// instead of a list or array, since each dialogue can be added lots -// of times. - -/* -int allDial[Dialogue*]; -int classDial[int][Dialogue*]; -int factionDial[int][Dialogue*]; -int actorDial[Item][Dialogue*]; -// If I look up cells on cell load, I don't have to resolve these -// names into anything! -int cellDial[char[]][Dialogue*]; -int raceDial[int][Dialogue*]; -*/ } #endif diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index 98786c20e3..d25072e548 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -79,7 +79,7 @@ void ESM::Variant::read (ESMReader& esm, Format format) else esm.fail ("illegal global variable type " + typeId); } - else // GMST + else if (format==Format_Gmst) { if (!esm.hasMoreSubs()) { @@ -106,6 +106,22 @@ void ESM::Variant::read (ESMReader& esm, Format format) esm.fail ("invalid subrecord: " + name.toString()); } } + else // info + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } setType (type); @@ -125,6 +141,9 @@ void ESM::Variant::write (ESMWriter& esm, Format format) const if (format==Format_Global) throw std::runtime_error ("can not serialise variant of type none to global format"); + if (format==Format_Info) + throw std::runtime_error ("can not serialise variant of type none to info format"); + // nothing to do here for GMST format } else diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index b78d647a82..8c5f3b3d47 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -32,7 +32,8 @@ namespace ESM enum Format { Format_Global, - Format_Gmst + Format_Gmst, + Format_Info }; Variant(); diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index 1b8cf4f875..160402aa4b 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -78,6 +78,9 @@ void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarTy if (format==Variant::Format_Global) esm.fail ("global variables of type string not supported"); + if (format==Variant::Format_Info) + esm.fail ("info variables of type string not supported"); + // GMST mValue = esm.getHString(); } @@ -90,6 +93,9 @@ void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarT if (format==Variant::Format_Global) throw std::runtime_error ("global variables of type string not supported"); + if (format==Variant::Format_Info) + throw std::runtime_error ("info variables of type string not supported"); + // GMST esm.writeHNString ("STRV", mValue); } @@ -154,10 +160,16 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT else esm.fail ("unsupported global variable integer type"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { if (type!=VT_Int) - esm.fail ("unsupported gmst variable integer type"); + { + std::ostringstream stream; + stream + << "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info") + << " variable integer type"; + esm.fail (stream.str()); + } esm.getHT (mValue); } @@ -179,10 +191,16 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var else throw std::runtime_error ("unsupported global variable integer type"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { if (type==VT_Int) - throw std::runtime_error ("unsupported global variable integer type"); + { + std::ostringstream stream; + stream + << "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info") + << " variable integer type"; + throw std::runtime_error (stream.str()); + } esm.writeHNT ("INTV", mValue); } @@ -234,7 +252,7 @@ void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarTyp { esm.getHNT (mValue, "FLTV"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { esm.getHT (mValue); } @@ -250,9 +268,9 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy esm.writeHNString ("FNAM", "f"); esm.writeHNT ("FLTV", mValue); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { - esm.writeHNT ("INTV", mValue); + esm.writeHNT ("FLTV", mValue); } } From 46de45b9a2a70ad4a67995a690a5ed2265f835c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 11:37:13 +0100 Subject: [PATCH 0607/1483] added var type column to globals --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 20 ++++++++++++++++---- apps/opencs/model/world/data.cpp | 5 +++-- apps/opencs/view/doc/viewmanager.cpp | 6 +++++- apps/opencs/view/world/vartypedelegate.cpp | 2 +- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 6a76b0b6ca..e709cc5bfd 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -152,7 +152,7 @@ void CSMDoc::Document::addOptionalGlobals() { ESM::Global global; global.mId = sGlobals[i]; - global.mValue.setType (ESM::VT_Int); + global.mValue.setType (ESM::VT_Long); addOptionalGlobal (global); } } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 40581972e9..c44abda2b2 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -30,7 +30,8 @@ namespace CSMWorld Display_Integer, Display_Float, Display_Var, - Display_VarType + Display_GmstVarType, + Display_GlobalVarType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 270987ec14..018825831b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -96,7 +96,7 @@ namespace CSMWorld template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_VarType) {} + VarTypeColumn (ColumnBase::Display display) : Column ("Type", display) {} virtual QVariant get (const Record& record) const { @@ -125,9 +125,19 @@ namespace CSMWorld { switch (record.get().mValue.getType()) { - case ESM::VT_String: return record.get().mValue.getString().c_str(); break; - case ESM::VT_Int: return record.get().mValue.getInteger(); break; - case ESM::VT_Float: return record.get().mValue.getFloat(); break; + case ESM::VT_String: + + return record.get().mValue.getString().c_str(); break; + + case ESM::VT_Int: + case ESM::VT_Short: + case ESM::VT_Long: + + return record.get().mValue.getInteger(); break; + + case ESM::VT_Float: + + return record.get().mValue.getFloat(); break; default: return QVariant(); } @@ -145,6 +155,8 @@ namespace CSMWorld break; case ESM::VT_Int: + case ESM::VT_Short: + case ESM::VT_Long: record2.mValue.setInteger (data.toInt()); break; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d4704b0c64..bbd8667b34 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -27,12 +27,13 @@ CSMWorld::Data::Data() mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); - mGlobals.addColumn (new FloatValueColumn); + mGlobals.addColumn (new VarTypeColumn (ColumnBase::Display_GlobalVarType)); + mGlobals.addColumn (new VarValueColumn); mGmsts.addColumn (new StringIdColumn); mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); - mGmsts.addColumn (new VarTypeColumn); + mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a8faefb970..718b807281 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -35,8 +35,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; - mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType, + mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, + new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); + } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index 3ee759ef2b..72cbaae428 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -85,7 +85,7 @@ void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) { { ESM::VT_None, "empty" }, { ESM::VT_Short, "short" }, - { ESM::VT_Int, "long" }, + { ESM::VT_Int, "integer" }, { ESM::VT_Long, "long" }, { ESM::VT_Float, "float" }, { ESM::VT_String, "string" }, From 2486ec6cb9edc637367bd95ff8081581a06d5f80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Mar 2013 13:51:48 +0100 Subject: [PATCH 0608/1483] Material fixes (vertex colors, alpha) --- apps/openmw/mwrender/renderingmanager.cpp | 6 +- components/nifogre/ogrenifloader.cpp | 11 +- files/materials/objects.mat | 14 +-- files/materials/objects.shader | 135 ++++++---------------- files/materials/terrain.shader | 21 +--- 5 files changed, 53 insertions(+), 134 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3f559c9fd4..44385e6623 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -102,6 +102,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Set default mipmap level (NB some APIs ignore this) // Mipmap generation is currently disabled because it causes issues on Intel/AMD //TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); + TextureManager::getSingleton().setDefaultNumMipmaps(0); // Set default texture filtering options TextureFilterOptions tfo; @@ -128,7 +129,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); sh::Factory::getInstance ().setGlobalSetting ("fog", "true"); - sh::Factory::getInstance ().setGlobalSetting ("lighting", "true"); sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); sh::Factory::getInstance ().setGlobalSetting ("terrain_num_lights", Settings::Manager::getString ("num lights", "Terrain")); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); @@ -329,8 +329,6 @@ void RenderingManager::update (float duration, bool paused) float *_playerPos = data.getPosition().pos; Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); - Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); - Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -353,6 +351,8 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); + Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); + applyFog(world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)); if(paused) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6f7afee434..7057c83e22 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -694,21 +694,24 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String sh::MaterialInstance* instance = sh::Factory::getInstance ().createMaterialInstance (matname, "openmw_objects_base"); if(vertMode == 0 || !vertexColour) { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, alpha))); + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); } else if(vertMode == 1) { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, alpha))); + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); } else if(vertMode == 2) { instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); } else std::cerr<< "Unhandled vertex mode: "< Date: Tue, 5 Mar 2013 14:24:29 +0100 Subject: [PATCH 0609/1483] Avoid manually updating render targets from within frameRenderingQueued --- apps/openmw/engine.cpp | 7 +++++++ apps/openmw/engine.hpp | 1 + apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwrender/water.cpp | 10 ++++++++-- apps/openmw/mwrender/water.hpp | 6 +++++- apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 1 + 9 files changed, 34 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ea6e0a2f52..62e106f3fb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -62,6 +62,13 @@ void OMW::Engine::setAnimationVerbose(bool animverbose) { } +bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) +{ + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame); + return true; +} + bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 572d1013e0..a4acee5232 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -105,6 +105,7 @@ namespace OMW void executeLocalScripts(); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); + virtual bool frameStarted (const Ogre::FrameEvent& evt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index eef844c761..654a59cea8 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -314,6 +314,7 @@ namespace MWBase /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void stopVideo() = 0; + virtual void frameStarted (float dt) = 0; }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 44385e6623..94daa8a01f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -939,4 +939,9 @@ void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, con mWater->updateEmitterPtr(old, ptr); } +void RenderingManager::frameStarted(float dt) +{ + mWater->frameStarted(dt); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e40672ada9..5cea241754 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -196,6 +196,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void playVideo(const std::string& name, bool allowSkipping); void stopVideo(); + void frameStarted(float dt); protected: virtual void windowResized(Ogre::RenderWindow* rw); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 2801e64942..c8b9db7f10 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -191,7 +191,8 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mWaterTimer(0.f), mReflection(NULL), mRefraction(NULL), - mSimulation(NULL) + mSimulation(NULL), + mPlayer(0,0) { mSimulation = new RippleSimulation(mSceneMgr); @@ -371,7 +372,12 @@ void Water::update(float dt, Ogre::Vector3 player) mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - mSimulation->update(dt, Ogre::Vector2(player.x, player.y)); + mPlayer = Ogre::Vector2(player.x, player.y); +} + +void Water::frameStarted(float dt) +{ + mSimulation->update(dt, mPlayer); if (mReflection) mReflection->update(); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 633a306640..6c03236370 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -98,7 +99,7 @@ namespace MWRender { }; /// Water rendering - class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener, public sh::MaterialInstanceListener + class Water : public sh::MaterialInstanceListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; @@ -139,6 +140,8 @@ namespace MWRender { Refraction* mRefraction; RippleSimulation* mSimulation; + Ogre::Vector2 mPlayer; + public: Water (Ogre::Camera *camera, RenderingManager* rend); ~Water(); @@ -147,6 +150,7 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); + void frameStarted(float dt); /// adds an emitter, position will be tracked automatically using its scene node void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cddcda68b2..970b339bd0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1469,4 +1469,9 @@ namespace MWWorld { mRendering->stopVideo(); } + + void World::frameStarted (float dt) + { + mRendering->frameStarted(dt); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0ae81b33a0..79d036e99d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -356,6 +356,7 @@ namespace MWWorld /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping); virtual void stopVideo(); + virtual void frameStarted (float dt); }; } From ff30bef3b2cc4a7186e8d928613adf292c1aa20b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Mar 2013 14:27:05 +0100 Subject: [PATCH 0610/1483] Mipmap fix --- files/materials/water.mat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/water.mat b/files/materials/water.mat index 3ea6a2c2bf..0ec71d2df7 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -37,7 +37,7 @@ material Water texture_unit normalMap { - direct_texture water_nm.png + texture water_nm.png 5 } texture_unit rippleNormalMap From 7f8d659f3cad7361b4b10ea7a23f12418d64c8b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Mar 2013 17:09:20 +0100 Subject: [PATCH 0611/1483] Fix transparency sorting --- components/nifogre/ogrenifloader.cpp | 3 ++- extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp | 9 +++++++++ extern/shiny/Platforms/Ogre/OgrePass.cpp | 7 ------- files/materials/objects.mat | 2 ++ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 7057c83e22..30c71023bc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -755,7 +755,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(!((alphaFlags>>13)&1) ? "on" : "off"))); + // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(!((alphaFlags>>13)&1) ? "force" : "off"))); instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp index 9f57c7b441..4ec43fcaeb 100644 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp @@ -1,5 +1,7 @@ #include "OgreMaterialSerializer.hpp" +#include + namespace sh { void OgreMaterialSerializer::reset() @@ -19,6 +21,13 @@ namespace sh bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass) { + // workaround https://ogre3d.atlassian.net/browse/OGRE-158 + if (param == "transparent_sorting" && value == "force") + { + pass->setTransparentSortingForced(true); + return true; + } + reset(); mScriptContext.section = Ogre::MSS_PASS; diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp index 8cfaae0788..3ed48b96f8 100644 --- a/extern/shiny/Platforms/Ogre/OgrePass.cpp +++ b/extern/shiny/Platforms/Ogre/OgrePass.cpp @@ -50,13 +50,6 @@ namespace sh return true; // handled already else if (name == "fragment_program") return true; // handled already - else if (name == "ffp_vertex_colour_ambient") - { - bool enabled = retrieveValue(value, context).get(); - // fixed-function vertex colour tracking - mPass->setVertexColourTracking(enabled ? Ogre::TVC_AMBIENT : Ogre::TVC_NONE); - return true; - } else { OgreMaterialSerializer& s = OgrePlatform::getSerializer(); diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 069a1036be..5e18a666a7 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -11,6 +11,7 @@ material openmw_objects_base scene_blend default depth_write default alpha_rejection default + transparent_sorting default pass { @@ -30,6 +31,7 @@ material openmw_objects_base scene_blend $scene_blend alpha_rejection $alpha_rejection depth_write $depth_write + transparent_sorting $transparent_sorting texture_unit diffuseMap { From 9133182f2fb87b3a02a35a853b22b0f37337a249 Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 5 Mar 2013 20:25:20 +0400 Subject: [PATCH 0612/1483] restore loading CELL records in esmtool --- components/esm/loadcell.cpp | 12 +++++++++++- components/esm/loadcell.hpp | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 92cb7d5ce8..76a48e5ec4 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -79,7 +79,7 @@ void CellRef::save(ESMWriter &esm) } } -void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) +void Cell::load(ESMReader &esm, bool saveContext) { // Ignore this for now, it might mean we should delete the entire // cell? @@ -127,6 +127,16 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) esm.getHT(mNAM0); } + if (saveContext) { + mContextList.push_back(esm.getContext()); + esm.skipRecord(); + } +} + +void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) +{ + this->load(esm, false); + // preload moved references while (esm.isNextSub("MVRF")) { CellRef ref; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 6bde9972d1..7db6dbe77c 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -174,7 +174,7 @@ struct Cell // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. - void load(ESMReader &esm) {}; + void load(ESMReader &esm, bool saveContext = true); void save(ESMWriter &esm); bool isExterior() const From 8b6f0e0770ef9672fc401618efa91eda52d19292 Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 5 Mar 2013 18:28:57 +0000 Subject: [PATCH 0613/1483] Correct orientation sign --- apps/openmw/mwrender/renderingmanager.cpp | 36 ++++++++++------------- apps/openmw/mwworld/physicssystem.cpp | 14 ++++----- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b214fd8009..abc1960b8d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -270,32 +270,28 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot if (!isPlayer && isActive) { - Ogre::Quaternion xr(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr(Ogre::Radian(rot.y), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr(Ogre::Radian(rot.z), Ogre::Vector3::UNIT_Z); + Ogre::Quaternion xr(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); - Ogre::Quaternion xref(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yref(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zref(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); + Ogre::Quaternion xref(Ogre::Radian(-ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yref(Ogre::Radian(-ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; - rot.x = newo.getPitch().valueRadians();// newo.x;Ogre::Quaternion:: - rot.y = newo.getYaw().valueRadians();//newo.y; - rot.z = newo.getRoll().valueRadians(); //newo.z; + Ogre::Quaternion newo = adjust ? (zr * yr * xr) * (zref*yref*xref) : zr * yr * xr; + Ogre::Radian ax,ay,az; + Ogre::Matrix3 mat; + newo.ToRotationMatrix(mat); + mat.ToEulerAnglesXYZ(ax,ay,az); + rot.x = -ax.valueRadians(); + rot.y = -ay.valueRadians(); + rot.z = -az.valueRadians(); ptr.getRefData().getBaseNode()->setOrientation(newo); } else if(isPlayer) { - rot.x = mPlayer->getPitch(); - rot.z = -mPlayer->getYaw(); - } - else if (adjust) - { - // Stored and passed in radians - float *f = ptr.getRefData().getPosition().rot; - rot.x += f[0]; - rot.y += f[1]; - rot.z += f[2]; + rot.x = -mPlayer->getPitch(); + rot.z = mPlayer->getYaw(); } return force; } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 316e57b789..c1c33cb5d0 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -99,9 +99,9 @@ namespace MWWorld if(!physicActor || !physicActor->getCollisionMode()) { // FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why? - return position + (Ogre::Quaternion(Ogre::Radian( refpos.rot[2]), Ogre::Vector3::UNIT_Z)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + return position + (Ogre::Quaternion(Ogre::Radian( -refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( -refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( -refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement; } @@ -115,9 +115,9 @@ namespace MWWorld Ogre::Vector3 velocity; if(!gravity) { - velocity = (Ogre::Quaternion(Ogre::Radian( refpos.rot[2]), Ogre::Vector3::UNIT_Z)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + velocity = (Ogre::Quaternion(Ogre::Radian( -refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( -refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( -refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement / time; } else @@ -128,7 +128,7 @@ namespace MWWorld if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) onground = true; } - velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::UNIT_Z)*movement / time; + velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)*movement / time; velocity.z += physicActor->getVerticalForce(); } From d3bf3812a44eb3f40eadf197d091cbc2d61b0cc0 Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 5 Mar 2013 20:16:57 +0000 Subject: [PATCH 0614/1483] changing rotation order (fix some misoriented objects) --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index abc1960b8d..8bad0d17e4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -278,7 +278,7 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot Ogre::Quaternion yref(Ogre::Radian(-ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Ogre::Quaternion newo = adjust ? (zr * yr * xr) * (zref*yref*xref) : zr * yr * xr; + Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; Ogre::Radian ax,ay,az; Ogre::Matrix3 mat; newo.ToRotationMatrix(mat); From c9859382bf70ef009a9a3f932e0a1ad6b2bf261d Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Wed, 6 Mar 2013 01:35:32 +0100 Subject: [PATCH 0615/1483] Made the launcher write the custom resolution to file, cleaned resolution parsing --- apps/launcher/graphicspage.cpp | 43 ++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 5905043548..6d5b3ab09e 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -190,11 +190,17 @@ void GraphicsPage::saveSettings() mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText()); - QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); - if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { - mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); - mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + if (standardRadioButton->isChecked()) { + QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); + + if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { + mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); + mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + } + } else { + mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value())); + mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value())); } } @@ -250,25 +256,26 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) for (opt_it = i->second.possibleValues.begin (); opt_it != i->second.possibleValues.end (); opt_it++, idx++) { - QString qval = QString::fromStdString(*opt_it).simplified(); - // remove extra tokens after the resolution (for example bpp, can be there or not depending on rendersystem) - QStringList tokens = qval.split(" ", QString::SkipEmptyParts); - assert (tokens.size() >= 3); + QRegExp resolutionRe(QString("(\\d+) x (\\d+)")); + QString resolution = QString::fromStdString(*opt_it).simplified(); - QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2); + if (resolutionRe.exactMatch(resolution)) { - QString aspect = getAspect(tokens.at(0).toInt(),tokens.at(2).toInt()); + int width = resolutionRe.cap(1).toInt(); + int height = resolutionRe.cap(2).toInt(); - if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { - resolutionStr.append(tr("\t(Widescreen ") + aspect + ")"); + QString aspect = getAspect(width, height); - } else if (aspect == QLatin1String("4:3")) { - resolutionStr.append(tr("\t(Standard 4:3)")); + if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { + resolution.append(tr("\t(Wide ") + aspect + ")"); + + } else if (aspect == QLatin1String("4:3")) { + resolution.append(tr("\t(Standard 4:3)")); + } + // do not add duplicate resolutions + if (!result.contains(resolution)) + result.append(resolution); } - - // do not add duplicate resolutions - if (!result.contains(resolutionStr)) - result << resolutionStr; } } From 39411eda7b663622582615d11e59c767e53dafc2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 15:11:40 +0100 Subject: [PATCH 0616/1483] Fix the spell buying window listing already owned spells --- apps/openmw/mwgui/spellbuyingwindow.cpp | 19 ++++++++++++++----- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 11f0904943..40fcf2988a 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -94,9 +94,6 @@ namespace MWGui mPtr = actor; clearSpells(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - - MWMechanics::Spells& playerSpells = MWWorld::Class::get (player).getCreatureStats (player).getSpells(); MWMechanics::Spells& merchantSpells = MWWorld::Class::get (actor).getCreatureStats (actor).getSpells(); for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) @@ -107,8 +104,8 @@ namespace MWGui if (spell->mData.mType!=ESM::Spell::ST_Spell) continue; // don't try to sell diseases, curses or powers - if (std::find (playerSpells.begin(), playerSpells.end(), *iter)!=playerSpells.end()) - continue; // we have that spell already + if (playerHasSpell(iter->first)) + continue; addSpell (iter->first); } @@ -118,6 +115,18 @@ namespace MWGui mSpellsView->setCanvasSize (MyGUI::IntSize(mSpellsView->getWidth(), std::max(mSpellsView->getHeight(), mCurrentY))); } + bool SpellBuyingWindow::playerHasSpell(const std::string &id) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::Spells& playerSpells = MWWorld::Class::get (player).getCreatureStats (player).getSpells(); + for (MWMechanics::Spells::TIterator it = playerSpells.begin(); it != playerSpells.end(); ++it) + { + if (Misc::StringUtils::ciEqual(id, it->first)) + return true; + } + return false; + } + void SpellBuyingWindow::onSpellButtonClick(MyGUI::Widget* _sender) { int price = *_sender->getUserData(); diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 1d0ac28e01..c4988fff35 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -47,6 +47,8 @@ namespace MWGui void updateLabels(); virtual void onReferenceUnavailable(); + + bool playerHasSpell (const std::string& id); }; } From 268bb235908be852c016e3339af60b260036a015 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 16:58:56 +0100 Subject: [PATCH 0617/1483] Implemented sneaking animation --- apps/openmw/mwclass/npc.cpp | 3 +-- apps/openmw/mwinput/inputmanagerimp.cpp | 15 +++++------- apps/openmw/mwinput/inputmanagerimp.hpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 32 +++++++++++++++---------- apps/openmw/mwmechanics/character.hpp | 6 +++++ apps/openmw/mwworld/player.cpp | 7 ++++++ apps/openmw/mwworld/player.hpp | 1 + 7 files changed, 42 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c8c61e118f..b1263c2e50 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -365,11 +365,10 @@ namespace MWClass fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; } - else if(Npc::getStance(ptr, Run, false)) + else if(Npc::getStance(ptr, Run, false) && !Npc::getStance(ptr, Sneak, false)) moveSpeed = runSpeed; else moveSpeed = walkSpeed; - if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) moveSpeed *= 0.75f; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 69de2988c8..4c10749b32 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -193,9 +193,6 @@ namespace MWInput case A_AutoMove: toggleAutoMove (); break; - case A_ToggleSneak: - /// \todo implement - break; case A_ToggleWalk: toggleWalking (); break; @@ -308,13 +305,13 @@ namespace MWInput else mPlayer.setForwardBackward (0); + mPlayer.setSneak(actionIsActive(A_Sneak)); + if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) { mPlayer.setUpDown (1); triedToMove = true; } - else if (actionIsActive(A_Crouch)) - mPlayer.setUpDown (-1); else mPlayer.setUpDown (0); @@ -364,7 +361,7 @@ namespace MWInput actionIsActive(A_MoveLeft) || actionIsActive(A_MoveRight) || actionIsActive(A_Jump) || - actionIsActive(A_Crouch) || + actionIsActive(A_Sneak) || actionIsActive(A_TogglePOV)) { resetIdleTime(); @@ -749,7 +746,7 @@ namespace MWInput defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1; defaultKeyBindings[A_Console] = OIS::KC_F2; defaultKeyBindings[A_Run] = OIS::KC_LSHIFT; - defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL; + defaultKeyBindings[A_Sneak] = OIS::KC_LCONTROL; defaultKeyBindings[A_AutoMove] = OIS::KC_Q; defaultKeyBindings[A_Jump] = OIS::KC_E; defaultKeyBindings[A_Journal] = OIS::KC_J; @@ -816,7 +813,7 @@ namespace MWInput descriptions[A_ToggleSpell] = "sReady_Magic"; descriptions[A_Console] = "sConsoleTitle"; descriptions[A_Run] = "sRun"; - descriptions[A_Crouch] = "sCrouch_Sneak"; + descriptions[A_Sneak] = "sCrouch_Sneak"; descriptions[A_AutoMove] = "sAuto_Run"; descriptions[A_Jump] = "sJump"; descriptions[A_Journal] = "sJournal"; @@ -865,7 +862,7 @@ namespace MWInput ret.push_back(A_MoveRight); ret.push_back(A_TogglePOV); ret.push_back(A_Run); - ret.push_back(A_Crouch); + ret.push_back(A_Sneak); ret.push_back(A_Activate); ret.push_back(A_ToggleWeapon); ret.push_back(A_ToggleSpell); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index d4f47723d8..8bb20b7bed 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -216,9 +216,9 @@ namespace MWInput A_CycleSpellRight, A_CycleWeaponLeft,//Cycling through weapons A_CycleWeaponRight, - A_ToggleSneak, //Toggles Sneak, add Push-Sneak later + A_ToggleSneak, //Toggles Sneak A_ToggleWalk, //Toggle Walking/Running - A_Crouch, + A_Sneak, A_QuickSave, A_QuickLoad, diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ae0114a351..62958db8d4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -46,6 +46,7 @@ static const struct { { CharState_Idle8, "idle8" }, { CharState_Idle9, "idle9" }, { CharState_IdleSwim, "idleswim" }, + { CharState_IdleSneak, "idlesneak" }, { CharState_WalkForward, "walkforward" }, { CharState_WalkBack, "walkback" }, @@ -67,6 +68,11 @@ static const struct { { CharState_SwimRunLeft, "swimrunleft" }, { CharState_SwimRunRight, "swimrunright" }, + { CharState_SneakForward, "sneakforward" }, + { CharState_SneakBack, "sneakback" }, + { CharState_SneakLeft, "sneakleft" }, + { CharState_SneakRight, "sneakright" }, + { CharState_Jump, "jump" }, { CharState_Death1, "death1" }, @@ -176,6 +182,7 @@ Ogre::Vector3 CharacterController::update(float duration) bool onground = world->isOnGround(mPtr); bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); + bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak); speed = cls.getSpeed(mPtr); /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except @@ -201,31 +208,30 @@ Ogre::Vector3 CharacterController::update(float duration) if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { if(vec.x > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunRight : CharState_RunRight) : - (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); + setState(inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight) + : (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight)), true); + else if(vec.x < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : - (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) + : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); + // Apply any forward/backward movement manually movement.y += vec.y * (speed*duration); } else if(vec.y != 0.0f && speed > 0.0f) { if(vec.y > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunForward : CharState_RunForward) : - (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + setState(inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward) + : (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward)), true); + else if(vec.y < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunBack : CharState_RunBack) : - (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) + : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true); // Apply any sideways movement manually movement.x += vec.x * (speed*duration); } else if(mAnimQueue.size() == 0) - setState((inwater ? CharState_IdleSwim : CharState_Idle), true); + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); } if(mAnimation && !mSkipAnim) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2b3c50864a..46f0690e77 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -25,6 +25,7 @@ enum CharacterState { CharState_Idle8, CharState_Idle9, CharState_IdleSwim, + CharState_IdleSneak, CharState_WalkForward, CharState_WalkBack, @@ -46,6 +47,11 @@ enum CharacterState { CharState_SwimRunLeft, CharState_SwimRunRight, + CharState_SneakForward, + CharState_SneakBack, + CharState_SneakLeft, + CharState_SneakRight, + CharState_Jump, /* Death states must be last! */ diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 76d44a5d7b..03dd1abc79 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -86,6 +86,13 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); } + void Player::setSneak(bool sneak) + { + MWWorld::Ptr ptr = getPlayer(); + + MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Sneak, sneak); + } + MWMechanics::DrawState_ Player::getDrawState() { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 4ef4d67717..5f2fc3a08b 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -67,6 +67,7 @@ namespace MWWorld void setRunState(bool run); void toggleRunning(); + void setSneak(bool sneak); }; } #endif From 66d2d3522f3fa94f73a0a23d942eb20b1405f0d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 18:03:47 +0100 Subject: [PATCH 0618/1483] Race selection preview: render only the head, and focus the camera on its node --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++++++--- apps/openmw/mwrender/characterpreview.hpp | 8 ++++++++ apps/openmw/mwrender/npcanimation.cpp | 15 ++++++++++++--- apps/openmw/mwrender/npcanimation.hpp | 5 ++++- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 4a3344e228..c99e426624 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -60,7 +60,7 @@ namespace MWRender mNode = renderRoot->createChildSceneNode(); mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0); + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); mNode->setVisible (false); @@ -102,7 +102,7 @@ namespace MWRender delete mAnimation; mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0); + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); mNode->setVisible (false); @@ -161,7 +161,7 @@ namespace MWRender RaceSelectionPreview::RaceSelectionPreview() : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(), - 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 120, -35), Ogre::Vector3(0,125,0)) + 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 6, -35), Ogre::Vector3(0,125,0)) , mRef(&mBase) { mBase = *mCharacter.get()->mBase; @@ -173,6 +173,8 @@ namespace MWRender mAnimation->runAnimation(0.0f); mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); + updateCamera(); + mNode->setVisible (true); mRenderTarget->update(); mNode->setVisible (false); @@ -189,5 +191,17 @@ namespace MWRender void RaceSelectionPreview::onSetup () { mAnimation->play("idle", "start", "stop", false); + + updateCamera(); + } + + void RaceSelectionPreview::updateCamera() + { + Ogre::Vector3 scale = mNode->getScale(); + Ogre::Vector3 headOffset = mAnimation->getHeadNode()->_getDerivedPosition(); + headOffset = mNode->convertLocalToWorldPosition(headOffset); + + mCamera->setPosition(headOffset + mPosition * scale); + mCamera->lookAt(headOffset + mPosition*Ogre::Vector3(0,1,0) * scale); } } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index cf1e250692..08cbd51087 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -36,6 +36,8 @@ namespace MWRender virtual void rebuild(); protected: + virtual bool renderHeadOnly() { return false; } + Ogre::TexturePtr mTexture; Ogre::RenderTarget* mRenderTarget; Ogre::Viewport* mViewport; @@ -82,6 +84,12 @@ namespace MWRender ESM::NPC mBase; MWWorld::LiveCellRef mRef; + protected: + + virtual bool renderHeadOnly() { return true; } + + void updateCamera(); + public: RaceSelectionPreview(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a7d5c22afc..9da70beb45 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -54,7 +54,7 @@ NpcAnimation::~NpcAnimation() } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly) : Animation(ptr), mStateID(-1), mTimeToChange(0), @@ -70,7 +70,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mPants(inv.end()), mGloveL(inv.end()), mGloveR(inv.end()), - mSkirtIter(inv.end()) + mSkirtIter(inv.end()), + mHeadOnly(headOnly) { mNpc = mPtr.get()->mBase; @@ -215,7 +216,7 @@ void NpcAnimation::updateParts(bool forceupdate) if(!forceupdate) return; - for(size_t i = 0;i < slotlistsize;i++) + for(size_t i = 0;i < slotlistsize && !mHeadOnly;i++) { MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); @@ -252,6 +253,9 @@ void NpcAnimation::updateParts(bool forceupdate) if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); + if (mHeadOnly) + return; + static const struct { ESM::PartReferenceType type; const char name[2][12]; @@ -449,4 +453,9 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorgetSkeleton()->getBone("Bip01 Head"); +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index aed4868bdd..5da4afef8a 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -39,6 +39,7 @@ private: std::string mHeadModel; std::string mHairModel; std::string mBodyPrefix; + bool mHeadOnly; float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; @@ -73,11 +74,13 @@ private: public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& inv, int visibilityFlags); + MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly=false); virtual ~NpcAnimation(); virtual Ogre::Vector3 runAnimation(float timepassed); + Ogre::Node* getHeadNode(); + void forceUpdate() { updateParts(true); } }; From 5938e19362a2acc7d6897be32724fda00c4b9398 Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 17:31:57 +0000 Subject: [PATCH 0619/1483] Clean up --- apps/openmw/mwrender/renderingmanager.cpp | 4 +++- libs/openengine/bullet/physic.cpp | 23 +++++++---------------- libs/openengine/bullet/physic.hpp | 8 ++++++++ libs/openengine/bullet/trace.cpp | 20 +------------------- 4 files changed, 19 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8bad0d17e4..1cd7c7a3e7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -279,13 +279,15 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; - Ogre::Radian ax,ay,az; + Ogre::Matrix3 mat; newo.ToRotationMatrix(mat); + Ogre::Radian ax,ay,az; mat.ToEulerAnglesXYZ(ax,ay,az); rot.x = -ax.valueRadians(); rot.y = -ay.valueRadians(); rot.z = -az.valueRadians(); + ptr.getRefData().getBaseNode()->setOrientation(newo); } else if(isPlayer) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 677d75f334..435ceef23e 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -13,18 +13,9 @@ #include #include -#define BIT(x) (1<<(x)) - namespace OEngine { namespace Physic { - enum collisiontypes { - COL_NOTHING = 0, //addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL); + dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); } void PhysicEngine::removeHeightField(int x, int y) @@ -401,11 +392,11 @@ namespace Physic return; if(body->mCollide) { - dynamicsWorld->addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL); + dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); } else { - dynamicsWorld->addRigidBody(body,COL_RAYCASTING,COL_RAYCASTING|COL_WORLD); + dynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_World); } body->setActivationState(DISABLE_DEACTIVATION); if(addToMap){ @@ -539,7 +530,7 @@ namespace Physic float d1 = 10000.; btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterMask = COL_WORLD|COL_RAYCASTING; + resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_Raycasting; dynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit()) { @@ -549,7 +540,7 @@ namespace Physic } btCollisionWorld::ClosestRayResultCallback resultCallback2(from, to); - resultCallback2.m_collisionFilterMask = COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL; + resultCallback2.m_collisionFilterMask = CollisionType_ActorInternal|CollisionType_ActorExternal; dynamicsWorld->rayTest(from, to, resultCallback2); float d2 = 10000.; if (resultCallback2.hasHit()) @@ -568,12 +559,12 @@ namespace Physic std::vector< std::pair > PhysicEngine::rayTest2(btVector3& from, btVector3& to) { MyRayResultCallback resultCallback1; - resultCallback1.m_collisionFilterMask = COL_WORLD|COL_RAYCASTING; + resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_Raycasting; dynamicsWorld->rayTest(from, to, resultCallback1); std::vector< std::pair > results = resultCallback1.results; MyRayResultCallback resultCallback2; - resultCallback2.m_collisionFilterMask = COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL; + resultCallback2.m_collisionFilterMask = CollisionType_ActorInternal|CollisionType_ActorExternal; dynamicsWorld->rayTest(from, to, resultCallback2); std::vector< std::pair > actorResults = resultCallback2.results; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index e579e35468..97fbbcea43 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -43,6 +43,14 @@ namespace Physic class PhysicEngine; class RigidBody; + enum CollisionType { + CollisionType_Nothing = 0, //dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); From 642653d10e12eeeb6cef02a63f62480687499bb6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 6 Mar 2013 19:57:00 +0100 Subject: [PATCH 0620/1483] World constructor fixes --- apps/openmw/mwworld/worldimp.cpp | 7 +++---- apps/openmw/mwworld/worldimp.hpp | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f9e4a743f5..7d3efe3e8c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -178,10 +178,11 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& master, const std::vector& plugins, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - ToUTF8::Utf8Encoder* encoder, std::map fallbackMap, int mActivationDistanceOverride) + ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), - mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride) + mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride), + mFallback (fallbackMap) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -247,8 +248,6 @@ namespace MWWorld mWorldScene = new Scene(*mRendering, mPhysics); - setFallbackValues(fallbackMap); - lastTick = mTimer.getMilliseconds(); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 79d036e99d..47088aa62c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -92,7 +92,7 @@ namespace MWWorld bool moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return true if the active cell (cell player is in) changed - + Ptr copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos); void updateWindowManager (); @@ -116,7 +116,7 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& master, const std::vector& plugins, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - ToUTF8::Utf8Encoder* encoder, std::map fallbackMap, int mActivationDistanceOverride); + ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride); virtual ~World(); @@ -174,11 +174,11 @@ namespace MWWorld virtual char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name. - + virtual std::vector getGlobals () const; - + virtual std::string getCurrentCellName () const; - + virtual void removeRefScript (MWWorld::RefData *ref); //< Remove the script attached to ref from mLocalScripts From f7d8f6456f13907502db90bf0540b20826886c1c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 20:45:11 +0100 Subject: [PATCH 0621/1483] Stats should never go below 0 --- apps/openmw/mwmechanics/stat.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index d576020c57..e1bb1994c8 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -28,7 +28,7 @@ namespace MWMechanics const T& getModified() const { - return mModified; + return std::max(static_cast(0), mModified); } T getModifier() const From 8be9627c8d62fa81cabd814e8382f9a55338301c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 21:26:41 +0100 Subject: [PATCH 0622/1483] Fix method signatures --- apps/openmw/mwmechanics/stat.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index e1bb1994c8..e9b7f43850 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -26,7 +26,7 @@ namespace MWMechanics return mBase; } - const T& getModified() const + T getModified() const { return std::max(static_cast(0), mModified); } @@ -108,7 +108,7 @@ namespace MWMechanics return mStatic.getBase(); } - const T& getModified() const + T getModified() const { return mStatic.getModified(); } From 5fc7103425732403a0b8e6f092430a2996138488 Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 20:31:47 +0000 Subject: [PATCH 0623/1483] First attempt at pathfinding using boost::graph --- apps/openmw/mwmechanics/aitravel.cpp | 193 ++++++++++++++++++++++++++- apps/openmw/mwmechanics/aitravel.hpp | 7 +- 2 files changed, 196 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 897dd17480..b5e67e449b 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,8 +1,19 @@ #include "aitravel.hpp" #include +#include "character.hpp" + +#include "../mwworld/class.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "movement.hpp" + +#include +#include +#include "boost/tuple/tuple.hpp" + MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z) +: mX(x),mY(y),mZ(z),isPathConstructed(false) { } @@ -11,10 +22,186 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } +float distance(ESM::Pathgrid::Point point,float x,float y,float z) +{ + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); +} + +float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) +{ + return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); +} + +int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) +{ + if(!grid) throw std::exception("NULL PathGrid!"); + if(grid->mPoints.empty()) throw std::exception("empty PathGrid!"); + + float m = distance(grid->mPoints[0],x,y,z); + int i0 = 0; + + for(int i=1; imPoints.size();i++) + { + if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); + i0 = i; + } + } + + return i0; +} + +float sgn(float a) +{ + if(a>0) return 1.; + else return -1.; +} + +float getZAngle(float dX,float dY) +{ + float h = sqrt(dX*dX+dY*dY); + return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); +} + +struct Edge +{ + float distance; +}; + +typedef boost::adjacency_list,boost::property > PathGridGraph; +typedef boost::property_map::type WeightMap; +typedef PathGridGraph::vertex_descriptor PointID; +typedef PathGridGraph::edge_descriptor PointConnectionID; + +struct found_path {}; + +class goalVisited : public boost::default_astar_visitor +{ +public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } +private: + PointID mGoal; +}; + +class DistanceHeuristic : public boost::astar_heuristic +{ +public: + DistanceHeuristic(const PathGridGraph & l, PointID goal) + : mGraph(l), mGoal(goal) {} + + float operator()(PointID u) + { + const ESM::Pathgrid::Point & U = mGraph[u]; + const ESM::Pathgrid::Point & V = mGraph[mGoal]; + float dx = U.mX - V.mX; + float dy = U.mY - V.mY; + float dz = U.mZ - V.mZ; + return sqrt(dx * dx + dy * dy + dz * dz); + } +private: + const PathGridGraph & mGraph; + PointID mGoal; +}; + +std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::vector p(boost::num_vertices(graph)); + std::vector d(boost::num_vertices(graph)); + std::list shortest_path; + + try { + boost::astar_search + ( + graph, + start, + DistanceHeuristic(graph,end), + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) + ); + + } catch(found_path fg) { + for(PointID v = end;; v = p[v]) { + shortest_path.push_front(graph[v]); + if(p[v] == v) + break; + } + } + return shortest_path; +} + +PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid) +{ + PathGridGraph graph; + + for(int i = 0;imPoints.size();i++) + { + PointID pID = boost::add_vertex(graph); + graph[pID] = pathgrid->mPoints[i]; + } + + for(int i = 0;imEdges.size();i++) + { + PointID u = pathgrid->mEdges[i].mV0; + PointID v = pathgrid->mEdges[i].mV1; + + PointConnectionID edge; + bool done; + boost::tie(edge,done) = boost::add_edge(u,v,graph); + WeightMap weightmap = boost::get(boost::edge_weight, graph); + weightmap[edge] = distance(graph[u],graph[v]); + + } + + return graph; +} + bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { - std::cout << "AiTravel completed.\n"; - return true; + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + ESM::Position pos = actor.getRefData().getPosition(); + + if(!isPathConstructed) + { + int start = getClosestPoint(pathgrid,pos.pos[0],pos.pos[1],pos.pos[2]); + int end = getClosestPoint(pathgrid,mX,mY,mZ); + + PathGridGraph graph = buildGraph(pathgrid); + + mPath = getPath(start,end,graph); + isPathConstructed = true; + } + if(mPath.empty()) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + if(distance(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) + { + mPath.pop_front(); + if(mPath.empty()) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + nextPoint = *mPath.begin(); + } + + float dX = nextPoint.mX - pos.pos[0]; + float dY = nextPoint.mY - pos.pos[1]; + + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + return false; + //return true; } int MWMechanics::AiTravel::getTypeId() const diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 1c6abbf279..a596f4c85d 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,7 +1,9 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H -#include "aipackage.hpp" +#include "aipackage.hpp" +#include "components\esm\loadpgrd.hpp" +#include namespace MWMechanics { @@ -21,6 +23,9 @@ namespace MWMechanics float mY; float mZ; + bool isPathConstructed; + std::list mPath; + }; } From 01908dbcc27f2202e13dce90fe24f77dc268c97c Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 21:17:33 +0000 Subject: [PATCH 0624/1483] little improvement --- apps/openmw/mwmechanics/aitravel.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b5e67e449b..9d41a080c7 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -22,6 +22,11 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } +float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) +{ + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); +} + float distance(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); @@ -64,11 +69,6 @@ float getZAngle(float dX,float dY) return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); } -struct Edge -{ - float distance; -}; - typedef boost::adjacency_list,boost::property > PathGridGraph; typedef boost::property_map::type WeightMap; @@ -176,6 +176,11 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) PathGridGraph graph = buildGraph(pathgrid); mPath = getPath(start,end,graph); + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + mPath.push_back(dest); isPathConstructed = true; } if(mPath.empty()) @@ -184,7 +189,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distance(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) + if(distanceZCorrected(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) { mPath.pop_front(); if(mPath.empty()) From 7504ae675b44c4ebea2509d8ef3e8381200111d3 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Thu, 7 Mar 2013 03:00:59 +0100 Subject: [PATCH 0625/1483] Implemented a file dialog for the editor using launcher .ui --- apps/launcher/CMakeLists.txt | 16 +- apps/launcher/datafilespage.cpp | 60 +--- apps/launcher/resources.qrc | 21 -- apps/opencs/CMakeLists.txt | 6 +- apps/opencs/editor.cpp | 101 ++++-- apps/opencs/editor.hpp | 15 +- apps/opencs/view/doc/filedialog.cpp | 272 ++++++++++++++++ apps/opencs/view/doc/filedialog.hpp | 66 ++++ components/CMakeLists.txt | 2 +- components/fileorderlist/datafileslist.cpp | 293 ------------------ components/fileorderlist/datafileslist.hpp | 75 ----- .../fileorderlist/model/datafilesmodel.cpp | 1 + .../fileorderlist/model/datafilesmodel.hpp | 3 + .../model/pluginsproxymodel.cpp | 0 .../model/pluginsproxymodel.hpp | 0 .../launcher}/icons/tango/document-new.png | Bin .../launcher}/icons/tango/edit-copy.png | Bin .../launcher}/icons/tango/edit-delete.png | Bin .../launcher}/icons/tango/go-bottom.png | Bin .../launcher}/icons/tango/go-down.png | Bin .../launcher}/icons/tango/go-top.png | Bin .../launcher}/icons/tango/go-up.png | Bin .../launcher}/icons/tango/index.theme | 0 .../launcher}/icons/tango/video-display.png | Bin .../launcher}/images/clear.png | Bin .../launcher}/images/down.png | Bin .../launcher}/images/openmw-header.png | Bin .../launcher}/images/openmw-plugin.png | Bin .../launcher}/images/openmw.ico | Bin .../launcher}/images/openmw.png | Bin .../launcher}/images/playpage-background.png | Bin files/launcher/launcher.qrc | 21 ++ {apps/launcher => files}/ui/datafilespage.ui | 2 +- {apps/launcher => files}/ui/graphicspage.ui | 0 {apps/launcher => files}/ui/mainwindow.ui | 0 {apps/launcher => files}/ui/playpage.ui | 0 36 files changed, 464 insertions(+), 490 deletions(-) delete mode 100644 apps/launcher/resources.qrc create mode 100644 apps/opencs/view/doc/filedialog.cpp create mode 100644 apps/opencs/view/doc/filedialog.hpp delete mode 100644 components/fileorderlist/datafileslist.cpp delete mode 100644 components/fileorderlist/datafileslist.hpp rename {apps/launcher => components/fileorderlist}/model/pluginsproxymodel.cpp (100%) rename {apps/launcher => components/fileorderlist}/model/pluginsproxymodel.hpp (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/document-new.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/edit-copy.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/edit-delete.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/go-bottom.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/go-down.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/go-top.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/go-up.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/index.theme (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/video-display.png (100%) rename {apps/launcher/resources => files/launcher}/images/clear.png (100%) rename {apps/launcher/resources => files/launcher}/images/down.png (100%) rename {apps/launcher/resources => files/launcher}/images/openmw-header.png (100%) rename {apps/launcher/resources => files/launcher}/images/openmw-plugin.png (100%) rename {apps/launcher/resources => files/launcher}/images/openmw.ico (100%) rename {apps/launcher/resources => files/launcher}/images/openmw.png (100%) rename {apps/launcher/resources => files/launcher}/images/playpage-background.png (100%) create mode 100644 files/launcher/launcher.qrc rename {apps/launcher => files}/ui/datafilespage.ui (98%) rename {apps/launcher => files}/ui/graphicspage.ui (100%) rename {apps/launcher => files}/ui/mainwindow.ui (100%) rename {apps/launcher => files}/ui/playpage.ui (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index a1c2289456..a63898c0ec 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -5,8 +5,6 @@ set(LAUNCHER maindialog.cpp playpage.cpp - model/pluginsproxymodel.cpp - settings/gamesettings.cpp settings/graphicssettings.cpp settings/launchersettings.cpp @@ -23,8 +21,6 @@ set(LAUNCHER_HEADER maindialog.hpp playpage.hpp - model/pluginsproxymodel.hpp - settings/gamesettings.hpp settings/graphicssettings.hpp settings/launchersettings.hpp @@ -42,17 +38,15 @@ set(LAUNCHER_HEADER_MOC maindialog.hpp playpage.hpp - model/pluginsproxymodel.hpp - utils/checkablemessagebox.hpp utils/textinputdialog.hpp ) set(LAUNCHER_UI - ui/datafilespage.ui - ui/graphicspage.ui - ui/mainwindow.ui - ui/playpage.ui + ../../files/ui/datafilespage.ui + ../../files/ui/graphicspage.ui + ../../files/ui/mainwindow.ui + ../../files/ui/playpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) @@ -66,7 +60,7 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -QT4_ADD_RESOURCES(RCC_SRCS resources.qrc) +QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 069cdd9ac9..90cdd29425 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -2,25 +2,21 @@ #include -#include #include #include +#include #include #include #include #include -#include "model/pluginsproxymodel.hpp" - #include "settings/gamesettings.hpp" #include "settings/launchersettings.hpp" #include "utils/textinputdialog.hpp" -using namespace ESM; -using namespace std; //sort QModelIndexList ascending bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2) @@ -100,60 +96,6 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam splitter->setSizes(sizeList); -// // Filter toolbar -// QLabel *filterLabel = new QLabel(tr("&Filter:"), this); -// LineEdit *filterLineEdit = new LineEdit(this); -// filterLabel->setBuddy(filterLineEdit); - -// QToolBar *filterToolBar = new QToolBar(this); -// filterToolBar->setMovable(false); - -// // Create a container widget and a layout to get the spacer to work -// QWidget *filterWidget = new QWidget(this); -// QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget); -// QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - -// filterLayout->addItem(hSpacer1); -// filterLayout->addWidget(filterLabel); -// filterLayout->addWidget(filterLineEdit); - -// filterToolBar->addWidget(filterWidget); - - - -// // Add both tables to a splitter -// mSplitter = new QSplitter(this); -// mSplitter->setOrientation(Qt::Horizontal); -// mSplitter->setChildrenCollapsible(false); // Don't allow the widgets to be hidden -// mSplitter->addWidget(mastersTable); -// mSplitter->addWidget(pluginsTable); - - - -// - -// // Bottom part with profile options -// QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); - -// profilesComboBox = new ProfilesComboBox(this); -// profilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); -// profilesComboBox->setInsertPolicy(QComboBox::NoInsert); -// profilesComboBox->setDuplicatesEnabled(false); -// profilesComboBox->setEditEnabled(false); - -// mProfileToolBar = new QToolBar(this); -// mProfileToolBar->setMovable(false); -// mProfileToolBar->setIconSize(QSize(16, 16)); - -// mProfileToolBar->addWidget(profileLabel); -// mProfileToolBar->addWidget(profilesComboBox); - -// QVBoxLayout *pageLayout = new QVBoxLayout(this); - -// pageLayout->addWidget(filterToolBar); -// pageLayout->addWidget(mSplitter); -// pageLayout->addWidget(mProfileToolBar); - // Create a dialog for the new profile name input mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); diff --git a/apps/launcher/resources.qrc b/apps/launcher/resources.qrc deleted file mode 100644 index 2b56f80fd6..0000000000 --- a/apps/launcher/resources.qrc +++ /dev/null @@ -1,21 +0,0 @@ - - - resources/images/clear.png - resources/images/down.png - resources/images/openmw.png - resources/images/openmw-plugin.png - resources/images/openmw-header.png - resources/images/playpage-background.png - - - resources/icons/tango/index.theme - resources/icons/tango/video-display.png - resources/icons/tango/document-new.png - resources/icons/tango/edit-copy.png - resources/icons/tango/edit-delete.png - resources/icons/tango/go-bottom.png - resources/icons/tango/go-down.png - resources/icons/tango/go-top.png - resources/icons/tango/go-up.png - - diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d5d389a141..0071dd1fc7 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units_noqt (model/tools opencs_units (view/doc - viewmanager view operations operation subview startup opendialog + viewmanager view operations operation subview startup filedialog ) @@ -76,6 +76,10 @@ set (OPENCS_US ) set (OPENCS_RES ../../files/opencs/resources.qrc + ../../files/launcher/launcher.qrc + ) + +set (OPENCS_UI ../../files/ui/datafilespage.ui ) source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e2df365a29..5966d089e3 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,14 +1,12 @@ #include "editor.hpp" -#include - #include #include "model/doc/document.hpp" #include "model/world/data.hpp" -CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) +CS::Editor::Editor() : mViewManager (mDocumentManager) { connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); @@ -16,42 +14,99 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); - connect (&mOpenDialog, SIGNAL(accepted()), this, SLOT(openFiles())); + connect (&mFileDialog, SIGNAL(openFiles()), this, SLOT(openFiles())); + connect (&mFileDialog, SIGNAL(createNewFile()), this, SLOT(createNewFile())); + + setupDataFiles(); +} + +void CS::Editor::setupDataFiles() +{ + boost::program_options::variables_map variables; + boost::program_options::options_description desc; + + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) + ("data-local", boost::program_options::value()->default_value("")) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("encoding", boost::program_options::value()->default_value("win1252")); + + boost::program_options::notify(variables); + + mCfgMgr.readConfiguration(variables, desc); + + Files::PathContainer mDataDirs, mDataLocal; + if (!variables["data"].empty()) { + mDataDirs = Files::PathContainer(variables["data"].as()); + } + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + mDataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + // Set the charset for reading the esm/esp files + QString encoding = QString::fromStdString(variables["encoding"].as()); + mFileDialog.setEncoding(encoding); + + Files::PathContainer dataDirs; + dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end()); + dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end()); + + for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + { + QString path = QString::fromStdString(iter->string()); + mFileDialog.addFiles(path); + } } void CS::Editor::createDocument() { mStartup.hide(); - /// \todo open the ESX picker instead - - std::ostringstream stream; - - stream << "NewDocument" << (++mNewDocumentIndex); - - std::vector files; - files.push_back (stream.str()); - - CSMDoc::Document *document = mDocumentManager.addDocument (files, true); - - mViewManager.addView (document); + mFileDialog.newFile(); } void CS::Editor::loadDocument() { mStartup.hide(); - mOpenDialog.show(); - mOpenDialog.raise(); - mOpenDialog.activateWindow(); + + mFileDialog.openFile(); } void CS::Editor::openFiles() { - std::vector paths; - mOpenDialog.getFileList(paths); - CSMDoc::Document *document = mDocumentManager.addDocument(paths, false); + std::vector files; + QStringList paths = mFileDialog.checkedItemsPaths(); + + foreach (const QString &path, paths) { + files.push_back(path.toStdString()); + } + + CSMDoc::Document *document = mDocumentManager.addDocument(files, false); mViewManager.addView (document); + mFileDialog.hide(); +} + +void CS::Editor::createNewFile() +{ + std::vector files; + QStringList paths = mFileDialog.checkedItemsPaths(); + + foreach (const QString &path, paths) { + files.push_back(path.toStdString()); + } + + files.push_back(mFileDialog.fileName().toStdString()); + + CSMDoc::Document *document = mDocumentManager.addDocument (files, true); + + mViewManager.addView (document); + mFileDialog.hide(); } int CS::Editor::run() @@ -59,4 +114,4 @@ int CS::Editor::run() mStartup.show(); return QApplication::exec(); -} \ No newline at end of file +} diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 024475bf01..c242a17ea8 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -3,11 +3,13 @@ #include +#include + #include "model/doc/documentmanager.hpp" #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" -#include "view/doc/opendialog.hpp" +#include "view/doc/filedialog.hpp" namespace CS { @@ -15,12 +17,14 @@ namespace CS { Q_OBJECT - int mNewDocumentIndex; ///< \todo remove when the proper new document dialogue is implemented. - CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; - OpenDialog mOpenDialog; + FileDialog mFileDialog; + + Files::ConfigurationManager mCfgMgr; + + void setupDataFiles(); // not implemented Editor (const Editor&); @@ -39,7 +43,8 @@ namespace CS void loadDocument(); void openFiles(); + void createNewFile(); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp new file mode 100644 index 0000000000..f956317a71 --- /dev/null +++ b/apps/opencs/view/doc/filedialog.cpp @@ -0,0 +1,272 @@ +#include "filedialog.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +FileDialog::FileDialog(QWidget *parent) : + QDialog(parent) +{ + setupUi(this); + + // Models + mDataFilesModel = new DataFilesModel(this); + + mMastersProxyModel = new QSortFilterProxyModel(); + mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm")); + mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mMastersProxyModel->setSourceModel(mDataFilesModel); + + mPluginsProxyModel = new PluginsProxyModel(); + mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); + mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mPluginsProxyModel->setSourceModel(mDataFilesModel); + + mFilterProxyModel = new QSortFilterProxyModel(); + mFilterProxyModel->setDynamicSortFilter(true); + mFilterProxyModel->setSourceModel(mPluginsProxyModel); + + QCheckBox checkBox; + unsigned int height = checkBox.sizeHint().height() + 4; + + mastersTable->setModel(mMastersProxyModel); + mastersTable->setObjectName("MastersTable"); + mastersTable->setContextMenuPolicy(Qt::CustomContextMenu); + mastersTable->setSortingEnabled(false); + mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); + mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); + mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + mastersTable->setAlternatingRowColors(true); + mastersTable->horizontalHeader()->setStretchLastSection(true); + + // Set the row height to the size of the checkboxes + mastersTable->verticalHeader()->setDefaultSectionSize(height); + mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + mastersTable->verticalHeader()->hide(); + + pluginsTable->setModel(mFilterProxyModel); + pluginsTable->setObjectName("PluginsTable"); + pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); + pluginsTable->setSortingEnabled(false); + pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); + pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); + pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + pluginsTable->setAlternatingRowColors(true); + pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); + pluginsTable->horizontalHeader()->setStretchLastSection(true); + + pluginsTable->verticalHeader()->setDefaultSectionSize(height); + pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + + // Hide the profile elements + profileLabel->hide(); + profilesComboBox->hide(); + newProfileButton->hide(); + deleteProfileButton->hide(); + + // Add some extra widgets + QHBoxLayout *nameLayout = new QHBoxLayout(); + QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + mNameLabel = new QLabel(tr("File Name:"), this); + + QRegExpValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$")); + mNameLineEdit = new LineEdit(this); + mNameLineEdit->setValidator(validator); + + nameLayout->addSpacerItem(spacer); + nameLayout->addWidget(mNameLabel); + nameLayout->addWidget(mNameLineEdit); + + mButtonBox = new QDialogButtonBox(this); + + mCreateButton = new QPushButton(tr("Create"), this); + mCreateButton->setEnabled(false); + + verticalLayout->addLayout(nameLayout); + verticalLayout->addWidget(mButtonBox); + + // Set sizes + QList sizeList; + sizeList << 175; + sizeList << 200; + + splitter->setSizes(sizeList); + + resize(600, 400); + + connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); + connect(mDataFilesModel, SIGNAL(checkedItemsChanged(QStringList)), this, SLOT(updateOpenButton(QStringList))); + connect(mNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateCreateButton(QString))); + + connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); + + connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + + connect(mCreateButton, SIGNAL(clicked()), this, SLOT(createButtonClicked())); + + connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); +} + +void FileDialog::updateViews() +{ + // Ensure the columns are hidden because sort() re-enables them + mastersTable->setColumnHidden(1, true); + mastersTable->setColumnHidden(3, true); + mastersTable->setColumnHidden(4, true); + mastersTable->setColumnHidden(5, true); + mastersTable->setColumnHidden(6, true); + mastersTable->setColumnHidden(7, true); + mastersTable->setColumnHidden(8, true); + mastersTable->resizeColumnsToContents(); + + pluginsTable->setColumnHidden(1, true); + pluginsTable->setColumnHidden(3, true); + pluginsTable->setColumnHidden(4, true); + pluginsTable->setColumnHidden(5, true); + pluginsTable->setColumnHidden(6, true); + pluginsTable->setColumnHidden(7, true); + pluginsTable->setColumnHidden(8, true); + pluginsTable->resizeColumnsToContents(); + +} + +void FileDialog::updateOpenButton(const QStringList &items) +{ + QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open); + + if (!openButton) + return; + + openButton->setEnabled(!items.isEmpty()); +} + +void FileDialog::updateCreateButton(const QString &name) +{ + if (!mCreateButton->isVisible()) + return; + + mCreateButton->setEnabled(!name.isEmpty()); +} + +void FileDialog::filterChanged(const QString &filter) +{ + QRegExp filterRe(filter, Qt::CaseInsensitive, QRegExp::FixedString); + mFilterProxyModel->setFilterRegExp(filterRe); +} + +void FileDialog::addFiles(const QString &path) +{ + mDataFilesModel->addFiles(path); + mDataFilesModel->sort(3); // Sort by date accessed +} + +void FileDialog::setEncoding(const QString &encoding) +{ + mDataFilesModel->setEncoding(encoding); +} + +void FileDialog::setCheckState(QModelIndex index) +{ + if (!index.isValid()) + return; + + QObject *object = QObject::sender(); + + // Not a signal-slot call + if (!object) + return; + + + if (object->objectName() == QLatin1String("PluginsTable")) { + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (sourceIndex.isValid()) { + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); + } + } + + if (object->objectName() == QLatin1String("MastersTable")) { + QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); + + if (sourceIndex.isValid()) { + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); + } + } + + return; +} + +QStringList FileDialog::checkedItemsPaths() +{ + return mDataFilesModel->checkedItemsPaths(); +} + +QString FileDialog::fileName() +{ + return mNameLineEdit->text(); +} + +void FileDialog::openFile() +{ + setWindowTitle(tr("Open")); + + mNameLabel->hide(); + mNameLineEdit->hide(); + mCreateButton->hide(); + + mButtonBox->removeButton(mCreateButton); + mButtonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Open); + QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open); + openButton->setEnabled(false); + + show(); + raise(); + activateWindow(); +} + +void FileDialog::newFile() +{ + setWindowTitle(tr("New")); + + mNameLabel->show(); + mNameLineEdit->clear(); + mNameLineEdit->show(); + mCreateButton->show(); + + mButtonBox->setStandardButtons(QDialogButtonBox::Cancel); + mButtonBox->addButton(mCreateButton, QDialogButtonBox::ActionRole); + + show(); + raise(); + activateWindow(); +} + +void FileDialog::accept() +{ + emit openFiles(); +} + +void FileDialog::createButtonClicked() +{ + emit createNewFile(); +} diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp new file mode 100644 index 0000000000..b21618d5de --- /dev/null +++ b/apps/opencs/view/doc/filedialog.hpp @@ -0,0 +1,66 @@ +#ifndef FILEDIALOG_HPP +#define FILEDIALOG_HPP + +#include +#include + +#include "ui_datafilespage.h" + +class QDialogButtonBox; +class QSortFilterProxyModel; +class QAbstractItemModel; +class QPushButton; +class QStringList; +class QString; +class QMenu; + +class DataFilesModel; +class PluginsProxyModel; + +class FileDialog : public QDialog, private Ui::DataFilesPage +{ + Q_OBJECT +public: + explicit FileDialog(QWidget *parent = 0); + void addFiles(const QString &path); + void setEncoding(const QString &encoding); + + void openFile(); + void newFile(); + void accepted(); + + QStringList checkedItemsPaths(); + QString fileName(); + +signals: + void openFiles(); + void createNewFile(); + +public slots: + void accept(); + +private slots: + void updateViews(); + void updateOpenButton(const QStringList &items); + void updateCreateButton(const QString &name); + void setCheckState(QModelIndex index); + + void filterChanged(const QString &filter); + + void createButtonClicked(); + +private: + QLabel *mNameLabel; + LineEdit *mNameLineEdit; + + QPushButton *mCreateButton; + QDialogButtonBox *mButtonBox; + + DataFilesModel *mDataFilesModel; + + PluginsProxyModel *mPluginsProxyModel; + QSortFilterProxyModel *mMastersProxyModel; + QSortFilterProxyModel *mFilterProxyModel; +}; + +#endif // FILEDIALOG_HPP diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7c52ab12cc..a4b194fab3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -70,7 +70,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui) if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (fileorderlist - datafileslist model/modelitem model/datafilesmodel model/esm/esmfile + model/modelitem model/datafilesmodel model/pluginsproxymodel model/esm/esmfile utils/profilescombobox utils/comboboxlineedit utils/lineedit utils/naturalsort ) diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp deleted file mode 100644 index 9fe8d0fea2..0000000000 --- a/components/fileorderlist/datafileslist.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include - -#include -#include - -#include "model/datafilesmodel.hpp" -#include "model/esm/esmfile.hpp" - -#include "utils/lineedit.hpp" - -#include "datafileslist.hpp" - -#include -/** - * Workaround for problems with whitespaces in paths in older versions of Boost library - */ -#if (BOOST_VERSION <= 104600) -namespace boost -{ - - template<> - inline boost::filesystem::path lexical_cast(const std::string& arg) - { - return boost::filesystem::path(arg); - } - -} /* namespace boost */ -#endif /* (BOOST_VERSION <= 104600) */ - -using namespace ESM; -using namespace std; - -//sort QModelIndexList ascending -bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2) -{ - return index1.row() >= index2.row(); -} - -//sort QModelIndexList descending -bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) -{ - return index1.row() <= index2.row(); -} - -DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) - : QWidget(parent) - , mCfgMgr(cfg) -{ - // Model - mFilesModel = new DataFilesModel(this); - - mFilesProxyModel = new QSortFilterProxyModel(); - mFilesProxyModel->setDynamicSortFilter(true); - mFilesProxyModel->setSourceModel(mFilesModel); - - // Filter toolbar - QLabel *filterLabel = new QLabel(tr("&Filter:"), this); - LineEdit *filterLineEdit = new LineEdit(this); - filterLabel->setBuddy(filterLineEdit); - - QToolBar *filterToolBar = new QToolBar(this); - filterToolBar->setMovable(false); - - // Create a container widget and a layout to get the spacer to work - QWidget *filterWidget = new QWidget(this); - QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget); - QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - filterLayout->addItem(hSpacer1); - filterLayout->addWidget(filterLabel); - filterLayout->addWidget(filterLineEdit); - - filterToolBar->addWidget(filterWidget); - - QCheckBox checkBox; - unsigned int height = checkBox.sizeHint().height() + 4; - - mFilesTable = new QTableView(this); - mFilesTable->setModel(mFilesProxyModel); - mFilesTable->setObjectName("PluginsTable"); - mFilesTable->setContextMenuPolicy(Qt::CustomContextMenu); - mFilesTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mFilesTable->setSelectionMode(QAbstractItemView::SingleSelection); - mFilesTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mFilesTable->setAlternatingRowColors(true); - mFilesTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); - mFilesTable->horizontalHeader()->setStretchLastSection(true); - mFilesTable->horizontalHeader()->hide(); - - mFilesTable->verticalHeader()->setDefaultSectionSize(height); - mFilesTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mFilesTable->setColumnHidden(1, true); - mFilesTable->setColumnHidden(2, true); - mFilesTable->setColumnHidden(3, true); - mFilesTable->setColumnHidden(4, true); - mFilesTable->setColumnHidden(5, true); - mFilesTable->setColumnHidden(6, true); - mFilesTable->setColumnHidden(7, true); - mFilesTable->setColumnHidden(8, true); - - QVBoxLayout *pageLayout = new QVBoxLayout(this); - - pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(mFilesTable); - - connect(mFilesTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - - connect(mFilesModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mFilesModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); - - connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - - connect(mFilesTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - - createActions(); -} - -void DataFilesList::createActions() -{ - // Refresh the plugins - QAction *refreshAction = new QAction(tr("Refresh"), this); - refreshAction->setShortcut(QKeySequence(tr("F5"))); - connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); - - // Context menu actions - mCheckAction = new QAction(tr("Check selected"), this); - connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check())); - - mUncheckAction = new QAction(tr("Uncheck selected"), this); - connect(mUncheckAction, SIGNAL(triggered()), this, SLOT(uncheck())); - - // Context menu for the plugins table - mContextMenu = new QMenu(this); - - mContextMenu->addAction(mCheckAction); - mContextMenu->addAction(mUncheckAction); - -} - -bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString encoding) -{ - // Set the charset for reading the esm/esp files - if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { - mFilesModel->setEncoding(encoding); - } - - // Add the paths to the respective models - for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { - QString path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - mFilesModel->addFiles(path); - } - - mFilesModel->sort(0); -// mMastersTable->sortByColumn(3, Qt::AscendingOrder); -// mPluginsTable->sortByColumn(3, Qt::AscendingOrder); - - return true; -} - -void DataFilesList::selectedFiles(std::vector& paths) -{ - QStringList pluginPaths = mFilesModel->checkedItemsPaths(); - foreach (const QString &path, pluginPaths) - { - paths.push_back(path.toStdString()); - } -} - -void DataFilesList::check() -{ - // Check the current selection - if (!mFilesTable->selectionModel()->hasSelection()) { - return; - } - - QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); - - //sort selection ascending because selectedIndexes returns an unsorted list - //qSort(indexes.begin(), indexes.end(), rowSmallerThan); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - mFilesModel->setCheckState(index, Qt::Checked); - } -} - -void DataFilesList::uncheck() -{ - // uncheck the current selection - if (!mFilesTable->selectionModel()->hasSelection()) { - return; - } - - QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); - - //sort selection ascending because selectedIndexes returns an unsorted list - //qSort(indexes.begin(), indexes.end(), rowSmallerThan); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - mFilesModel->setCheckState(index, Qt::Unchecked); - } -} - -void DataFilesList::refresh() -{ - mFilesModel->sort(0); - - - // Refresh the plugins table - mFilesTable->scrollToTop(); -} - - -void DataFilesList::setCheckState(QModelIndex index) -{ - if (!index.isValid()) - return; - - QObject *object = QObject::sender(); - - // Not a signal-slot call - if (!object) - return; - - if (object->objectName() == QLatin1String("PluginsTable")) { - QModelIndex sourceIndex = mFilesProxyModel->mapToSource(index); - - (mFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mFilesModel->setCheckState(sourceIndex, Qt::Unchecked) - : mFilesModel->setCheckState(sourceIndex, Qt::Checked); - } - - return; - -} - -void DataFilesList::uncheckAll() -{ - mFilesModel->uncheckAll(); -} - -void DataFilesList::filterChanged(const QString filter) -{ - QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); - mFilesProxyModel->setFilterRegExp(regExp); -} - -void DataFilesList::showContextMenu(const QPoint &point) -{ - // Make sure there are plugins in the view - if (!mFilesTable->selectionModel()->hasSelection()) { - return; - } - - QPoint globalPos = mFilesTable->mapToGlobal(point); - - QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); - - // Show the check/uncheck actions depending on the state of the selected items - mUncheckAction->setEnabled(false); - mCheckAction->setEnabled(false); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - (mFilesModel->checkState(index) == Qt::Checked) - ? mUncheckAction->setEnabled(true) - : mCheckAction->setEnabled(true); - } - - // Show menu - mContextMenu->exec(globalPos); -} - -void DataFilesList::setCheckState(const QString& element, Qt::CheckState state) -{ - EsmFile *file = mFilesModel->findItem(element); - if (file) - { - mFilesModel->setCheckState(mFilesModel->indexFromItem(file), Qt::Checked); - } -} - -QStringList DataFilesList::checkedFiles() -{ - return mFilesModel->checkedItems(); -} diff --git a/components/fileorderlist/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp deleted file mode 100644 index 69a20393c2..0000000000 --- a/components/fileorderlist/datafileslist.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef DATAFILESLIST_H -#define DATAFILESLIST_H - -#include -#include -#include - - -class QTableView; -class QSortFilterProxyModel; -class QSettings; -class QAction; -class QToolBar; -class QMenu; -class ProfilesComboBox; -class DataFilesModel; - -class TextInputDialog; - -namespace Files { struct ConfigurationManager; } - -class DataFilesList : public QWidget -{ - Q_OBJECT - -public: - DataFilesList(Files::ConfigurationManager& cfg, QWidget *parent = 0); - - bool setupDataFiles(Files::PathContainer dataDirs, const QString encoding); - void selectedFiles(std::vector& paths); - void uncheckAll(); - QStringList checkedFiles(); - void setCheckState(const QString& element, Qt::CheckState); - - -public slots: - void setCheckState(QModelIndex index); - - void filterChanged(const QString filter); - void showContextMenu(const QPoint &point); - - // Action slots -// void moveUp(); -// void moveDown(); -// void moveTop(); -// void moveBottom(); - void check(); - void uncheck(); - void refresh(); - -private: - DataFilesModel *mFilesModel; - - QSortFilterProxyModel *mFilesProxyModel; - - QTableView *mFilesTable; - - QMenu *mContextMenu; - -// QAction *mMoveUpAction; -// QAction *mMoveDownAction; -// QAction *mMoveTopAction; -// QAction *mMoveBottomAction; - QAction *mCheckAction; - QAction *mUncheckAction; - - Files::ConfigurationManager &mCfgMgr; - -// const QStringList checkedPlugins(); -// const QStringList selectedMasters(); - - void createActions(); -}; - -#endif diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 4e9b69dc27..b33e2e12ab 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -212,6 +212,7 @@ bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, in QModelIndex lastIndex = indexFromItem(mFiles.last()); emit dataChanged(firstIndex, lastIndex); + emit checkedItemsChanged(checkedItems()); return true; } diff --git a/components/fileorderlist/model/datafilesmodel.hpp b/components/fileorderlist/model/datafilesmodel.hpp index 0e5008abe1..0a07a536f8 100644 --- a/components/fileorderlist/model/datafilesmodel.hpp +++ b/components/fileorderlist/model/datafilesmodel.hpp @@ -48,6 +48,9 @@ public: QModelIndex indexFromItem(EsmFile *item) const; EsmFile* findItem(const QString &name); EsmFile* item(int row) const; + +signals: + void checkedItemsChanged(const QStringList &items); private: bool canBeChecked(EsmFile *file) const; diff --git a/apps/launcher/model/pluginsproxymodel.cpp b/components/fileorderlist/model/pluginsproxymodel.cpp similarity index 100% rename from apps/launcher/model/pluginsproxymodel.cpp rename to components/fileorderlist/model/pluginsproxymodel.cpp diff --git a/apps/launcher/model/pluginsproxymodel.hpp b/components/fileorderlist/model/pluginsproxymodel.hpp similarity index 100% rename from apps/launcher/model/pluginsproxymodel.hpp rename to components/fileorderlist/model/pluginsproxymodel.hpp diff --git a/apps/launcher/resources/icons/tango/document-new.png b/files/launcher/icons/tango/document-new.png similarity index 100% rename from apps/launcher/resources/icons/tango/document-new.png rename to files/launcher/icons/tango/document-new.png diff --git a/apps/launcher/resources/icons/tango/edit-copy.png b/files/launcher/icons/tango/edit-copy.png similarity index 100% rename from apps/launcher/resources/icons/tango/edit-copy.png rename to files/launcher/icons/tango/edit-copy.png diff --git a/apps/launcher/resources/icons/tango/edit-delete.png b/files/launcher/icons/tango/edit-delete.png similarity index 100% rename from apps/launcher/resources/icons/tango/edit-delete.png rename to files/launcher/icons/tango/edit-delete.png diff --git a/apps/launcher/resources/icons/tango/go-bottom.png b/files/launcher/icons/tango/go-bottom.png similarity index 100% rename from apps/launcher/resources/icons/tango/go-bottom.png rename to files/launcher/icons/tango/go-bottom.png diff --git a/apps/launcher/resources/icons/tango/go-down.png b/files/launcher/icons/tango/go-down.png similarity index 100% rename from apps/launcher/resources/icons/tango/go-down.png rename to files/launcher/icons/tango/go-down.png diff --git a/apps/launcher/resources/icons/tango/go-top.png b/files/launcher/icons/tango/go-top.png similarity index 100% rename from apps/launcher/resources/icons/tango/go-top.png rename to files/launcher/icons/tango/go-top.png diff --git a/apps/launcher/resources/icons/tango/go-up.png b/files/launcher/icons/tango/go-up.png similarity index 100% rename from apps/launcher/resources/icons/tango/go-up.png rename to files/launcher/icons/tango/go-up.png diff --git a/apps/launcher/resources/icons/tango/index.theme b/files/launcher/icons/tango/index.theme similarity index 100% rename from apps/launcher/resources/icons/tango/index.theme rename to files/launcher/icons/tango/index.theme diff --git a/apps/launcher/resources/icons/tango/video-display.png b/files/launcher/icons/tango/video-display.png similarity index 100% rename from apps/launcher/resources/icons/tango/video-display.png rename to files/launcher/icons/tango/video-display.png diff --git a/apps/launcher/resources/images/clear.png b/files/launcher/images/clear.png similarity index 100% rename from apps/launcher/resources/images/clear.png rename to files/launcher/images/clear.png diff --git a/apps/launcher/resources/images/down.png b/files/launcher/images/down.png similarity index 100% rename from apps/launcher/resources/images/down.png rename to files/launcher/images/down.png diff --git a/apps/launcher/resources/images/openmw-header.png b/files/launcher/images/openmw-header.png similarity index 100% rename from apps/launcher/resources/images/openmw-header.png rename to files/launcher/images/openmw-header.png diff --git a/apps/launcher/resources/images/openmw-plugin.png b/files/launcher/images/openmw-plugin.png similarity index 100% rename from apps/launcher/resources/images/openmw-plugin.png rename to files/launcher/images/openmw-plugin.png diff --git a/apps/launcher/resources/images/openmw.ico b/files/launcher/images/openmw.ico similarity index 100% rename from apps/launcher/resources/images/openmw.ico rename to files/launcher/images/openmw.ico diff --git a/apps/launcher/resources/images/openmw.png b/files/launcher/images/openmw.png similarity index 100% rename from apps/launcher/resources/images/openmw.png rename to files/launcher/images/openmw.png diff --git a/apps/launcher/resources/images/playpage-background.png b/files/launcher/images/playpage-background.png similarity index 100% rename from apps/launcher/resources/images/playpage-background.png rename to files/launcher/images/playpage-background.png diff --git a/files/launcher/launcher.qrc b/files/launcher/launcher.qrc new file mode 100644 index 0000000000..19b1c5a6f4 --- /dev/null +++ b/files/launcher/launcher.qrc @@ -0,0 +1,21 @@ + + + images/clear.png + images/down.png + images/openmw.png + images/openmw-plugin.png + images/openmw-header.png + images/playpage-background.png + + + icons/tango/index.theme + icons/tango/video-display.png + icons/tango/document-new.png + icons/tango/edit-copy.png + icons/tango/edit-delete.png + icons/tango/go-bottom.png + icons/tango/go-down.png + icons/tango/go-top.png + icons/tango/go-up.png + + diff --git a/apps/launcher/ui/datafilespage.ui b/files/ui/datafilespage.ui similarity index 98% rename from apps/launcher/ui/datafilespage.ui rename to files/ui/datafilespage.ui index 91b5475e67..044817fb40 100644 --- a/apps/launcher/ui/datafilespage.ui +++ b/files/ui/datafilespage.ui @@ -59,7 +59,7 @@ - + Current Profile: diff --git a/apps/launcher/ui/graphicspage.ui b/files/ui/graphicspage.ui similarity index 100% rename from apps/launcher/ui/graphicspage.ui rename to files/ui/graphicspage.ui diff --git a/apps/launcher/ui/mainwindow.ui b/files/ui/mainwindow.ui similarity index 100% rename from apps/launcher/ui/mainwindow.ui rename to files/ui/mainwindow.ui diff --git a/apps/launcher/ui/playpage.ui b/files/ui/playpage.ui similarity index 100% rename from apps/launcher/ui/playpage.ui rename to files/ui/playpage.ui From a994a23f4ec1a1fe956216651caea2ff7bd0a127 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Mar 2013 07:56:29 +0100 Subject: [PATCH 0626/1483] file loading fixes --- apps/opencs/model/doc/document.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e709cc5bfd..11d877d0b1 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -18,9 +18,6 @@ void CSMDoc::Document::load (const std::vector::const_i if (lastAsModified) getData().loadFile (*end2, false); - - addOptionalGmsts(); - addOptionalGlobals(); } void CSMDoc::Document::addOptionalGmsts() @@ -199,6 +196,8 @@ void CSMDoc::Document::createBase() getData().getGlobals().add (record); } + + /// \todo add GMSTs } CSMDoc::Document::Document (const std::vector& files, bool new_) @@ -213,7 +212,9 @@ CSMDoc::Document::Document (const std::vector& files, b mName = files.back().filename().string(); - if (files.size()>1 || !new_) + if (new_ && files.size()==1) + createBase(); + else if (files.size()>1) { std::vector::const_iterator end = files.end(); @@ -223,8 +224,8 @@ CSMDoc::Document::Document (const std::vector& files, b load (files.begin(), end, !new_); } - if (new_ && files.size()==1) - createBase(); + addOptionalGmsts(); + addOptionalGlobals(); connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); From e34685b8a314d49d6353876c3634022a5ad444af Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Mar 2013 12:46:26 +0100 Subject: [PATCH 0627/1483] Fix manually changed mouse cursor --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/cursor.cpp | 5 +++-- apps/openmw/mwgui/hud.cpp | 11 +++++------ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 81d7cb9fed..93cc8e44a2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -237,6 +237,8 @@ namespace MWBase virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; + virtual void changePointer (const std::string& name) = 0; + virtual const Translation::Storage& getTranslationDataStorage() const = 0; }; } diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 399695ae3f..b0d164bedf 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -13,8 +13,9 @@ namespace MWGui { - ResourceImageSetPointerFix::ResourceImageSetPointerFix() : - mImageSet(NULL) + ResourceImageSetPointerFix::ResourceImageSetPointerFix() + : mImageSet(NULL) + , mRotation(0) { } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index cebc457db8..0a31a428b8 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -4,7 +4,6 @@ #include #include -#include #include @@ -222,7 +221,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) else world->dropObjectOnGround(world->getPlayer().getPlayer(), object); - MyGUI::PointerManager::getInstance().setPointer("arrow"); + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); std::string sound = MWWorld::Class::get(object).getDownSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); @@ -273,21 +272,21 @@ void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) bool canDrop = world->canPlaceObject(mouseX, mouseY); if (!canDrop) - MyGUI::PointerManager::getInstance().setPointer("drop_ground"); + MWBase::Environment::get().getWindowManager()->changePointer("drop_ground"); else - MyGUI::PointerManager::getInstance().setPointer("arrow"); + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); } else { - MyGUI::PointerManager::getInstance().setPointer("arrow"); + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); mWorldMouseOver = true; } } void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) { - MyGUI::PointerManager::getInstance().setPointer("arrow"); + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); mWorldMouseOver = false; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eb8d4c1911..d866ec7557 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1127,3 +1127,8 @@ const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; } + +void WindowManager::changePointer(const std::string &name) +{ + mCursor->onCursorChange(name); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7786af31a1..122b10cc39 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -228,6 +228,8 @@ namespace MWGui virtual void startEnchanting(MWWorld::Ptr actor); virtual void startTraining(MWWorld::Ptr actor); + virtual void changePointer (const std::string& name); + virtual const Translation::Storage& getTranslationDataStorage() const; private: From 0ee0dbdb971bb5ae09ef256173f69d46ba1cd303 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Mar 2013 14:00:13 +0100 Subject: [PATCH 0628/1483] Added "dispose corpse" button, added stealing (all items visible and no penalty yet) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwgui/container.cpp | 66 +++++++++++++++++++--- apps/openmw/mwgui/container.hpp | 10 +++- apps/openmw/mwgui/inventorywindow.cpp | 18 ------ apps/openmw/mwgui/inventorywindow.hpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 27 +-------- apps/openmw/mwgui/tradewindow.hpp | 4 -- apps/openmw/mwworld/actionopen.cpp | 6 +- apps/openmw/mwworld/actionopen.hpp | 8 ++- files/mygui/openmw_container_window.layout | 4 ++ 11 files changed, 87 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 90dc707152..19f327dcbb 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -132,7 +132,7 @@ namespace MWClass const MWWorld::Ptr& actor) const { if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - return boost::shared_ptr (new MWWorld::ActionOpen(ptr)); + return boost::shared_ptr (new MWWorld::ActionOpen(ptr, true)); else return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b1263c2e50..f074d03684 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -220,7 +220,9 @@ namespace MWClass const MWWorld::Ptr& actor) const { if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - return boost::shared_ptr (new MWWorld::ActionOpen(ptr)); + return boost::shared_ptr (new MWWorld::ActionOpen(ptr, true)); + else if (MWWorld::Class::get(actor).getStance(actor, MWWorld::Class::Sneak)) + return boost::shared_ptr (new MWWorld::ActionOpen(ptr)); // stealing else return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 479a82efab..2b80003127 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -15,6 +15,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -70,9 +71,11 @@ namespace } -ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) : - mDragAndDrop(dragAndDrop), - mFilter(ContainerBase::Filter_All) +ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) + : mDragAndDrop(dragAndDrop) + , mFilter(ContainerBase::Filter_All) + , mDisplayEquippedItems(true) + , mHighlightEquippedItems(true) { } @@ -313,7 +316,6 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); } - std::cout << "container weight " << curWeight << "/" << capacity << std::endl; } else { @@ -430,7 +432,7 @@ void ContainerBase::drawItems() equippedItems.erase(found); } // and add the items that are left (= have the correct category) - if (!ignoreEquippedItems()) + if (mDisplayEquippedItems && mHighlightEquippedItems) { for (std::vector::const_iterator it=equippedItems.begin(); it != equippedItems.end(); ++it) @@ -445,7 +447,8 @@ void ContainerBase::drawItems() std::vector regularItems; for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) { - if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() + if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() + || (!mHighlightEquippedItems && mDisplayEquippedItems)) && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) regularItems.push_back(*iter); @@ -587,6 +590,27 @@ void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) } } +std::vector ContainerBase::getEquippedItems() +{ + if (mPtr.getTypeName() != typeid(ESM::NPC).name()) + return std::vector(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + + std::vector items; + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) + { + items.push_back(*it); + } + } + + return items; +} + MWWorld::ContainerStore& ContainerBase::getContainerStore() { MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); @@ -599,6 +623,7 @@ ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAnd : ContainerBase(dragAndDrop) , WindowBase("openmw_container_window.layout", parWindowManager) { + getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mTakeButton, "TakeButton"); getWidget(mCloseButton, "CloseButton"); @@ -608,6 +633,7 @@ ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAnd getWidget(itemView, "ItemView"); setWidgets(containerWidget, itemView); + mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); @@ -625,8 +651,18 @@ void ContainerWindow::onWindowResize(MyGUI::Window* window) drawItems(); } -void ContainerWindow::open(MWWorld::Ptr container) +void ContainerWindow::open(MWWorld::Ptr container, bool loot) { + mDisplayEquippedItems = true; + mHighlightEquippedItems = false; + if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) + { + // we are stealing stuff + mDisplayEquippedItems = false; + } + + mDisposeCorpseButton->setVisible(loot); + openContainer(container); setTitle(MWWorld::Class::get(container).getName(container)); drawItems(); @@ -671,6 +707,22 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) } } +void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) +{ + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + onTakeAllButtonClicked(mTakeButton); + + /// \todo I don't think this is the correct flag to check + if (MWWorld::Class::get(mPtr).isEssential(mPtr)) + mWindowManager.messageBox("#{sDisposeCorpseFail}"); + else + MWBase::Environment::get().getWorld()->deleteObject(mPtr); + + mPtr = MWWorld::Ptr(); + } +} + void ContainerWindow::onReferenceUnavailable() { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 08d425032f..3c8127b26c 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -82,6 +82,9 @@ namespace MWGui void drawItems(); protected: + bool mDisplayEquippedItems; + bool mHighlightEquippedItems; + MyGUI::ScrollView* mItemView; MyGUI::Widget* mContainerWidget; @@ -111,14 +114,13 @@ namespace MWGui virtual bool isTradeWindow() { return false; } virtual bool isInventory() { return false; } - virtual std::vector getEquippedItems() { return std::vector(); } + virtual std::vector getEquippedItems(); virtual void _unequipItem(MWWorld::Ptr item) { ; } virtual bool isTrading() { return false; } virtual void onSelectedItemImpl(MWWorld::Ptr item) { ; } - virtual bool ignoreEquippedItems() { return false; } virtual std::vector itemsToIgnore() { return std::vector(); } virtual void notifyContentChanged() { ; } @@ -131,15 +133,17 @@ namespace MWGui virtual ~ContainerWindow(); - void open(MWWorld::Ptr container); + void open(MWWorld::Ptr container, bool loot=false); protected: + MyGUI::Button* mDisposeCorpseButton; MyGUI::Button* mTakeButton; MyGUI::Button* mCloseButton; void onWindowResize(MyGUI::Window* window); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); + void onDisposeCorpseButtonClicked(MyGUI::Widget* sender); virtual void onReferenceUnavailable(); }; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4a02346445..ab7615c0ef 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -211,24 +211,6 @@ namespace MWGui return MWWorld::Ptr(); } - std::vector InventoryWindow::getEquippedItems() - { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - - std::vector items; - - for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) - { - MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); - if (it != invStore.end()) - { - items.push_back(*it); - } - } - - return items; - } - void InventoryWindow::_unequipItem(MWWorld::Ptr item) { MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 6b45a99800..7c59bab506 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -64,7 +64,6 @@ namespace MWGui virtual bool isTrading() { return mTrading; } virtual bool isInventory() { return true; } - virtual std::vector getEquippedItems(); virtual void _unequipItem(MWWorld::Ptr item); virtual void onReferenceUnavailable() { ; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index e3cf8ea3a7..1b82d741c1 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -31,6 +31,9 @@ namespace MWGui , mBalanceButtonsState(BBS_None) , mBalanceChangePause(0.0) { + // items the NPC is wearing should not be for trade + mDisplayEquippedItems = true; + MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; getWidget(containerWidget, "Items"); @@ -337,30 +340,6 @@ namespace MWGui mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(getMerchantGold())); } - std::vector TradeWindow::getEquippedItems() - { - std::vector items; - - if (mPtr.getTypeName() == typeid(ESM::Creature).name()) - { - // creatures don't have equipment slots. - return items; - } - - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - - for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) - { - MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); - if (it != invStore.end()) - { - items.push_back(*it); - } - } - - return items; - } - bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item) { int services = 0; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index ea749f5a24..2e05d03d51 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -82,10 +82,6 @@ namespace MWGui void onIncreaseButtonTriggered(); void onDecreaseButtonTriggered(); - // don't show items that the NPC has equipped in his trade-window. - virtual bool ignoreEquippedItems() { return true; } - virtual std::vector getEquippedItems(); - virtual bool isTrading() { return true; } virtual bool isTradeWindow() { return true; } diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 040a3856e8..728b6e32bf 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -10,7 +10,9 @@ namespace MWWorld { - ActionOpen::ActionOpen (const MWWorld::Ptr& container) : Action (false, container) + ActionOpen::ActionOpen (const MWWorld::Ptr& container, bool loot) + : Action (false, container) + , mLoot(loot) { } @@ -20,6 +22,6 @@ namespace MWWorld return; MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget()); + MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget(), mLoot); } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index c49ebefa51..8578995aee 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -13,8 +13,12 @@ namespace MWWorld virtual void executeImp (const MWWorld::Ptr& actor); public: - ActionOpen (const Ptr& container); - ///< \param The Container the Player has activated. + ActionOpen (const Ptr& container, bool loot=false); + ///< \param container The Container the Player has activated. + /// \param loot If true, display the "dispose of corpse" button + + private: + bool mLoot; }; } diff --git a/files/mygui/openmw_container_window.layout b/files/mygui/openmw_container_window.layout index 94e9458a5b..452196aaea 100644 --- a/files/mygui/openmw_container_window.layout +++ b/files/mygui/openmw_container_window.layout @@ -15,6 +15,10 @@ + + + + From 66a754e9aa515b5b5c9e993e8608ef501b59110c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Mar 2013 15:25:22 +0100 Subject: [PATCH 0629/1483] Fix tooltip position when hovering the crosshair over NPCs --- apps/openmw/mwworld/worldimp.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7d3efe3e8c..33a9b52bf6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -996,13 +996,7 @@ namespace MWWorld if (!object.isEmpty ()) { Ogre::SceneNode* node = object.getRefData().getBaseNode(); - Ogre::AxisAlignedBox bounds; - int i; - for (i=0; inumAttachedObjects(); ++i) - { - Ogre::MovableObject* ob = node->getAttachedObject(i); - bounds.merge(ob->getWorldBoundingBox()); - } + Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); if (bounds.isFinite()) { Vector4 screenCoords = mRendering->boundingBoxToScreen(bounds); From f2f4b6e2d5f5e91f752f7f42860118a739a3e865 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Thu, 7 Mar 2013 20:15:01 +0100 Subject: [PATCH 0630/1483] Make MWWorld::getInterior case insensitive. Interior cells names can use different mix of uppercase/lowercase in different places. getInterior() should return same cell in all cases. Fixes bug #586. --- apps/openmw/mwworld/cells.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index b912f5ccca..f95d30df13 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -129,13 +129,14 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name) { - std::map::iterator result = mInteriors.find (name); + std::string lowerName = Misc::StringUtils::lowerCase(name); + std::map::iterator result = mInteriors.find (lowerName); if (result==mInteriors.end()) { - const ESM::Cell *cell = mStore.get().find(name); + const ESM::Cell *cell = mStore.get().find(lowerName); - result = mInteriors.insert (std::make_pair (name, Ptr::CellStore (cell))).first; + result = mInteriors.insert (std::make_pair (lowerName, Ptr::CellStore (cell))).first; } if (result->second.mState!=Ptr::CellStore::State_Loaded) From 3adf3f51212c4330010bf04c63687b7593c29b6f Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 5 Mar 2013 00:45:25 +0100 Subject: [PATCH 0631/1483] Revive bsatool --- CMakeLists.txt | 13 ++- apps/bsatool/CMakeLists.txt | 26 ++++++ apps/bsatool/bsatool.cpp | 86 +++++++++++++++++ .../bsa/tests => apps/bsatool}/bsatool.ggo | 0 .../bsa/tests => apps/bsatool}/bsatool_cmd.c | 62 ++++++------- .../bsa/tests => apps/bsatool}/bsatool_cmd.h | 6 +- components/bsa/tests/Makefile | 9 +- components/bsa/tests/bsatool.cpp | 92 ------------------- 8 files changed, 159 insertions(+), 135 deletions(-) create mode 100644 apps/bsatool/CMakeLists.txt create mode 100644 apps/bsatool/bsatool.cpp rename {components/bsa/tests => apps/bsatool}/bsatool.ggo (100%) rename {components/bsa/tests => apps/bsatool}/bsatool_cmd.c (99%) rename {components/bsa/tests => apps/bsatool}/bsatool_cmd.h (98%) delete mode 100644 components/bsa/tests/bsatool.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6498e723c2..3950274790 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) # Apps and tools +option(BUILD_BSATOOL "build BSA extractor" OFF) option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) @@ -352,7 +353,7 @@ if(DPKG_PROGRAM) Data files from the original game is required to run it.") SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") - SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") + SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") @@ -446,6 +447,10 @@ add_subdirectory (components) # Apps and tools add_subdirectory( apps/openmw ) +if (BUILD_BSATOOL) + add_subdirectory( apps/bsatool ) +endif() + if (BUILD_ESMTOOL) add_subdirectory( apps/esmtool ) endif() @@ -532,6 +537,9 @@ if (WIN32) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif (BUILD_LAUNCHER) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) + if (BUILD_BSATOOL) + set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS}) + endif (BUILD_BSATOOL) if (BUILD_ESMTOOL) set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif (BUILD_ESMTOOL) @@ -656,6 +664,9 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) IF(BUILD_LAUNCHER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER) + IF(BUILD_BSATOOL) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_BSATOOL) IF(BUILD_ESMTOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESMTOOL) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt new file mode 100644 index 0000000000..8e33f0675c --- /dev/null +++ b/apps/bsatool/CMakeLists.txt @@ -0,0 +1,26 @@ +set(BSATOOL + bsatool.cpp + bsatool_cmd.c + bsatool_cmd.h +) +source_group(apps\\bsatool FILES ${BSATOOL}) + +# Main executable +add_executable(bsatool + ${BSATOOL} +) + +target_link_libraries(bsatool + ${Boost_LIBRARIES} + components +) + +#if (APPLE) +# find_library(CARBON_FRAMEWORK Carbon) +# target_link_libraries(openmw ${CARBON_FRAMEWORK}) +#endif (APPLE) + +if (BUILD_WITH_CODE_COVERAGE) + add_definitions (--coverage) + target_link_libraries(bsatool gcov) +endif() diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp new file mode 100644 index 0000000000..2d15f8cf7c --- /dev/null +++ b/apps/bsatool/bsatool.cpp @@ -0,0 +1,86 @@ +#include + +#include "bsatool_cmd.h" + +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + gengetopt_args_info info; + + if(cmdline_parser(argc, argv, &info) != 0) + return 1; + + if(info.inputs_num != 1) + { + if(info.inputs_num == 0) + std::cout << "ERROR: missing BSA file\n\n"; + else + std::cout << "ERROR: more than one BSA file specified\n\n"; + cmdline_parser_print_help(); + return 1; + } + + // Open file + Bsa::BSAFile bsa; + char *arcname = info.inputs[0]; + try { bsa.open(arcname); } + catch(std::exception &e) + { + std::cout << "ERROR reading BSA archive '" << arcname + << "'\nDetails:\n" << e.what() << std::endl; + return 2; + } + + if(info.extract_given) + { + char *file = info.extract_arg; + + if(!bsa.exists(file)) + { + std::cout << "ERROR: file '" << file << "' not found\n"; + std::cout << "In archive: " << arcname << std::endl; + return 3; + } + + // Find the base name of the file + int pos = strlen(file); + while(pos > 0 && file[pos] != '\\') pos--; + char *base = file+pos+1; + + // TODO: We might add full directory name extraction later. We + // could also allow automatic conversion from / to \ in + // parameter file names. + + // Load the file into a memory buffer + Ogre::DataStreamPtr data = bsa.getFile(file); + + // Write the file to disk + std::ofstream out(base, std::ios::binary); + out.write(data->getAsString().c_str(), data->size()); + out.close(); + + return 0; + } + + // List all files + const Bsa::BSAFile::FileList &files = bsa.getList(); + for(int i=0; i -#include +#include +#include #include #ifndef FIX_UNUSED @@ -71,7 +71,7 @@ void clear_args (struct gengetopt_args_info *args_info) FIX_UNUSED (args_info); args_info->extract_arg = NULL; args_info->extract_orig = NULL; - + } static @@ -83,7 +83,7 @@ void init_args_info(struct gengetopt_args_info *args_info) args_info->version_help = gengetopt_args_info_help[1] ; args_info->extract_help = gengetopt_args_info_help[2] ; args_info->long_help = gengetopt_args_info_help[3] ; - + } void @@ -133,7 +133,7 @@ void cmdline_parser_params_init(struct cmdline_parser_params *params) { if (params) - { + { params->override = 0; params->initialize = 1; params->check_required = 1; @@ -145,9 +145,9 @@ cmdline_parser_params_init(struct cmdline_parser_params *params) struct cmdline_parser_params * cmdline_parser_params_create(void) { - struct cmdline_parser_params *params = + struct cmdline_parser_params *params = (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); - cmdline_parser_params_init(params); + cmdline_parser_params_init(params); return params; } @@ -168,8 +168,8 @@ cmdline_parser_release (struct gengetopt_args_info *args_info) unsigned int i; free_string_field (&(args_info->extract_arg)); free_string_field (&(args_info->extract_orig)); - - + + for (i = 0; i < args_info->inputs_num; ++i) free (args_info->inputs [i]); @@ -211,7 +211,7 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) write_into_file(outfile, "extract", args_info->extract_orig, 0); if (args_info->long_given) write_into_file(outfile, "long", 0, 0 ); - + i = EXIT_SUCCESS; return i; @@ -276,7 +276,7 @@ cmdline_parser_ext (int argc, char * const *argv, struct gengetopt_args_info *ar cmdline_parser_free (args_info); exit (EXIT_FAILURE); } - + return result; } @@ -285,7 +285,7 @@ cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_ { int result; struct cmdline_parser_params params; - + params.override = override; params.initialize = initialize; params.check_required = check_required; @@ -299,7 +299,7 @@ cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_ cmdline_parser_free (args_info); exit (EXIT_FAILURE); } - + return result; } @@ -324,7 +324,7 @@ cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog * */ -/* +/* * we must include anything we need since this file is not thought to be * inserted in a file already using getopt.h * @@ -859,7 +859,7 @@ static int getopt_internal_r(int argc, char *const *argv, const char *optstring, return -1; d->custom_optarg = NULL; - /* + /* * This is a big difference with GNU getopt, since optind == 0 * means initialization while here 1 means first call. */ @@ -926,7 +926,7 @@ static char *package_name = 0; */ static int update_arg(void *field, char **orig_field, - unsigned int *field_given, unsigned int *prev_given, + unsigned int *field_given, unsigned int *prev_given, char *value, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, @@ -947,18 +947,18 @@ int update_arg(void *field, char **orig_field, if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) { if (short_opt != '-') - fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", + fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", package_name, long_opt, short_opt, (additional_error ? additional_error : "")); else - fprintf (stderr, "%s: `--%s' option given more than once%s\n", + fprintf (stderr, "%s: `--%s' option given more than once%s\n", package_name, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } FIX_UNUSED (default_value); - + if (field_given && *field_given && ! override) return 0; if (prev_given) @@ -1011,7 +1011,7 @@ cmdline_parser_internal ( int error = 0; struct gengetopt_args_info local_args_info; - + int override; int initialize; int check_required; @@ -1021,9 +1021,9 @@ cmdline_parser_internal ( int optind; int opterr; int optopt; - + package_name = argv[0]; - + override = params->override; initialize = params->initialize; check_required = params->check_required; @@ -1078,28 +1078,28 @@ cmdline_parser_internal ( exit (EXIT_SUCCESS); case 'x': /* Extract file from archive. */ - - - if (update_arg( (void *)&(args_info->extract_arg), + + + if (update_arg( (void *)&(args_info->extract_arg), &(args_info->extract_orig), &(args_info->extract_given), &(local_args_info.extract_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "extract", 'x', additional_error)) goto failure; - + break; case 'l': /* Include extra information in archive listing. */ - - - if (update_arg( 0 , + + + if (update_arg( 0 , 0 , &(args_info->long_given), &(local_args_info.long_given), optarg, 0, 0, ARG_NO, check_ambiguity, override, 0, 0, "long", 'l', additional_error)) goto failure; - + break; case 0: /* Long option with no short option */ @@ -1140,7 +1140,7 @@ cmdline_parser_internal ( return 0; failure: - + cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } diff --git a/components/bsa/tests/bsatool_cmd.h b/apps/bsatool/bsatool_cmd.h similarity index 98% rename from components/bsa/tests/bsatool_cmd.h rename to apps/bsatool/bsatool_cmd.h index 98fe2633fe..4d5f80ea27 100644 --- a/components/bsa/tests/bsatool_cmd.h +++ b/apps/bsatool/bsatool_cmd.h @@ -13,7 +13,7 @@ #include "config.h" #endif -#include /* for FILE */ +#include /* for FILE */ #ifdef __cplusplus extern "C" { @@ -43,7 +43,7 @@ struct gengetopt_args_info char * extract_orig; /**< @brief Extract file from archive original value given at command line. */ const char *extract_help; /**< @brief Extract file from archive help description. */ const char *long_help; /**< @brief Include extra information in archive listing help description. */ - + unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int extract_given ; /**< @brief Whether extract was given. */ @@ -136,7 +136,7 @@ void cmdline_parser_print_help(void); void cmdline_parser_print_version(void); /** - * Initializes all the fields a cmdline_parser_params structure + * Initializes all the fields a cmdline_parser_params structure * to their default values * @param params the structure to initialize */ diff --git a/components/bsa/tests/Makefile b/components/bsa/tests/Makefile index bc2bf4e50f..73e20d7b3a 100644 --- a/components/bsa/tests/Makefile +++ b/components/bsa/tests/Makefile @@ -1,6 +1,6 @@ GCC=g++ -all: bsa_file_test bsatool ogre_archive_test +all: bsa_file_test ogre_archive_test I_OGRE=$(shell pkg-config --cflags OGRE) L_OGRE=$(shell pkg-config --libs OGRE) @@ -11,12 +11,5 @@ bsa_file_test: bsa_file_test.cpp ../bsa_file.cpp ogre_archive_test: ogre_archive_test.cpp ../bsa_file.cpp ../bsa_archive.cpp $(GCC) $^ -o $@ $(I_OGRE) $(L_OGRE) -bsatool: bsatool.cpp ../bsa_file.cpp bsatool_cmd.c - $(GCC) $^ -o $@ - -bsatool_cmd.c: bsatool.ggo - gengetopt < bsatool.ggo - clean: rm *_test - rm bsatool diff --git a/components/bsa/tests/bsatool.cpp b/components/bsa/tests/bsatool.cpp deleted file mode 100644 index df37e3827c..0000000000 --- a/components/bsa/tests/bsatool.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "../bsa_file.hpp" - -#include "bsatool_cmd.h" - -#include -#include -#include -#include - -#include "../../mangle/stream/filters/buffer_stream.hpp" - -using namespace std; -using namespace Mangle::Stream; -using namespace Bsa; - -int main(int argc, char** argv) -{ - gengetopt_args_info info; - - if(cmdline_parser(argc, argv, &info) != 0) - return 1; - - if(info.inputs_num != 1) - { - if(info.inputs_num == 0) - cout << "ERROR: missing BSA file\n\n"; - else - cout << "ERROR: more than one BSA file specified\n\n"; - cmdline_parser_print_help(); - return 1; - } - - // Open file - BSAFile bsa; - char *arcname = info.inputs[0]; - try { bsa.open(arcname); } - catch(exception &e) - { - cout << "ERROR reading BSA archive '" << arcname - << "'\nDetails:\n" << e.what() << endl; - return 2; - } - - if(info.extract_given) - { - char *file = info.extract_arg; - - if(!bsa.exists(file)) - { - cout << "ERROR: file '" << file << "' not found\n"; - cout << "In archive: " << arcname << endl; - return 3; - } - - // Find the base name of the file - int pos = strlen(file); - while(pos > 0 && file[pos] != '\\') pos--; - char *base = file+pos+1; - - // TODO: We might add full directory name extraction later. We - // could also allow automatic conversion from / to \ in - // parameter file names. - - // Load the file into a memory buffer - BufferStream data(bsa.getFile(file)); - - // Write the file to disk - ofstream out(base, ios::binary); - out.write((char*)data.getPtr(), data.size()); - out.close(); - - return 0; - } - - // List all files - const BSAFile::FileList &files = bsa.getList(); - for(int i=0; i Date: Thu, 7 Mar 2013 21:05:56 +0100 Subject: [PATCH 0632/1483] Bsatool: extract and extractall modes --- apps/bsatool/CMakeLists.txt | 7 - apps/bsatool/bsatool.cpp | 304 ++++++++-- apps/bsatool/bsatool.ggo | 11 - apps/bsatool/bsatool_cmd.c | 1146 ----------------------------------- apps/bsatool/bsatool_cmd.h | 179 ------ 5 files changed, 253 insertions(+), 1394 deletions(-) delete mode 100644 apps/bsatool/bsatool.ggo delete mode 100644 apps/bsatool/bsatool_cmd.c delete mode 100644 apps/bsatool/bsatool_cmd.h diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 8e33f0675c..3f1988a709 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -1,7 +1,5 @@ set(BSATOOL bsatool.cpp - bsatool_cmd.c - bsatool_cmd.h ) source_group(apps\\bsatool FILES ${BSATOOL}) @@ -15,11 +13,6 @@ target_link_libraries(bsatool components ) -#if (APPLE) -# find_library(CARBON_FRAMEWORK Carbon) -# target_link_libraries(openmw ${CARBON_FRAMEWORK}) -#endif (APPLE) - if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 2d15f8cf7c..e6fcc2567d 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -1,76 +1,192 @@ +#include +#include +#include + +#include +#include +#include + #include -#include "bsatool_cmd.h" +#define BSATOOL_VERSION 1.1 -#include -#include -#include -#include +// Create local aliases for brevity +namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; + +struct Arguments +{ + std::string mode; + std::string filename; + std::string extractfile; + std::string outdir; + + bool longformat; + bool fullpath; +}; + +void replaceAll(std::string& str, const std::string& needle, const std::string& substitute) +{ + int pos = str.find(needle); + while(pos != -1) + { + str.replace(pos, needle.size(), substitute); + pos = str.find(needle); + } +} + +bool parseOptions (int argc, char** argv, Arguments &info) +{ + bpo::options_description desc("Inspect and extract files from Bethesda BSA archives\n\n" + "Usages:\n" + " bsatool list [-l] archivefile\n" + " List the files presents in the input archive.\n\n" + " bsatool extract [-f] archivefile [file_to_extract] [output_directory]\n" + " Extract a file from the input archive.\n\n" + " bsatool extractall archivefile [output_directory]\n" + " Extract all files from the input archive.\n\n" + "Allowed options"); + + desc.add_options() + ("help,h", "print help message.") + ("version,v", "print version information and quit.") + ("long,l", "Include extra information in archive listing.") + ("full-path,f", "Create diretory hierarchy on file extraction " + "(always true for extractall).") + ; + + // input-file is hidden and used as a positional argument + bpo::options_description hidden("Hidden Options"); + + hidden.add_options() + ( "mode,m", bpo::value(), "bsatool mode") + ( "input-file,i", bpo::value< std::vector >(), "input file") + ; + + bpo::positional_options_description p; + p.add("mode", 1).add("input-file", 3); + + // there might be a better way to do this + bpo::options_description all; + all.add(desc).add(hidden); + + bpo::variables_map variables; + try + { + bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv) + .options(all).positional(p).run(); + bpo::store(valid_opts, variables); + } + catch(std::exception &e) + { + std::cout << "ERROR parsing arguments: " << e.what() << "\n\n" + << desc << std::endl; + return false; + } + + bpo::notify(variables); + + if (variables.count ("help")) + { + std::cout << desc << std::endl; + return false; + } + if (variables.count ("version")) + { + std::cout << "BSATool version " << BSATOOL_VERSION << std::endl; + return false; + } + if (!variables.count("mode")) + { + std::cout << "ERROR: no mode specified!\n\n" + << desc << std::endl; + return false; + } + + info.mode = variables["mode"].as(); + if (!(info.mode == "list" || info.mode == "extract" || info.mode == "extractall")) + { + std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"\n\n" + << desc << std::endl; + return false; + } + + if (!variables.count("input-file")) + { + std::cout << "\nERROR: missing BSA archive\n\n" + << desc << std::endl; + return false; + } + info.filename = variables["input-file"].as< std::vector >()[0]; + + // Default output to the working directory + info.outdir = "."; + + if (info.mode == "extract") + { + if (variables["input-file"].as< std::vector >().size() < 2) + { + std::cout << "\nERROR: file to extract unspecified\n\n" + << desc << std::endl; + return false; + } + if (variables["input-file"].as< std::vector >().size() > 1) + info.extractfile = variables["input-file"].as< std::vector >()[1]; + if (variables["input-file"].as< std::vector >().size() > 2) + info.outdir = variables["input-file"].as< std::vector >()[2]; + } + else if (variables["input-file"].as< std::vector >().size() > 1) + info.outdir = variables["input-file"].as< std::vector >()[1]; + + info.longformat = variables.count("long"); + info.fullpath = variables.count("full-path"); + + return true; +} + +int list(Bsa::BSAFile& bsa, Arguments& info); +int extract(Bsa::BSAFile& bsa, Arguments& info); +int extractAll(Bsa::BSAFile& bsa, Arguments& info); int main(int argc, char** argv) { - gengetopt_args_info info; - - if(cmdline_parser(argc, argv, &info) != 0) + Arguments info; + if(!parseOptions (argc, argv, info)) return 1; - if(info.inputs_num != 1) - { - if(info.inputs_num == 0) - std::cout << "ERROR: missing BSA file\n\n"; - else - std::cout << "ERROR: more than one BSA file specified\n\n"; - cmdline_parser_print_help(); - return 1; - } - // Open file Bsa::BSAFile bsa; - char *arcname = info.inputs[0]; - try { bsa.open(arcname); } + try + { + bsa.open(info.filename); + } catch(std::exception &e) { - std::cout << "ERROR reading BSA archive '" << arcname + std::cout << "ERROR reading BSA archive '" << info.filename << "'\nDetails:\n" << e.what() << std::endl; return 2; } - if(info.extract_given) + if (info.mode == "list") + return list(bsa, info); + else if (info.mode == "extract") + return extract(bsa, info); + else if (info.mode == "extractall") + return extractAll(bsa, info); + else { - char *file = info.extract_arg; - - if(!bsa.exists(file)) - { - std::cout << "ERROR: file '" << file << "' not found\n"; - std::cout << "In archive: " << arcname << std::endl; - return 3; - } - - // Find the base name of the file - int pos = strlen(file); - while(pos > 0 && file[pos] != '\\') pos--; - char *base = file+pos+1; - - // TODO: We might add full directory name extraction later. We - // could also allow automatic conversion from / to \ in - // parameter file names. - - // Load the file into a memory buffer - Ogre::DataStreamPtr data = bsa.getFile(file); - - // Write the file to disk - std::ofstream out(base, std::ios::binary); - out.write(data->getAsString().c_str(), data->size()); - out.close(); - - return 0; + std::cout << "Unsupported mode. That is not supposed to happen." << std::endl; + return 1; } +} +int list(Bsa::BSAFile& bsa, Arguments& info) +{ // List all files const Bsa::BSAFile::FileList &files = bsa.getList(); for(int i=0; igetAsString().c_str(), data->size()); + out.close(); + + return 0; +} + +int extractAll(Bsa::BSAFile& bsa, Arguments& info) +{ + // Get the list of files present in the archive + Bsa::BSAFile::FileList list = bsa.getList(); + + // Iter on the list + for(Bsa::BSAFile::FileList::iterator it = list.begin(); it != list.end(); ++it) { + const char* archivePath = it->name; + + std::string extractPath (archivePath); + replaceAll(extractPath, "\\", "/"); + + // Get the target path (the path the file will be extracted to) + bfs::path target (info.outdir); + target /= extractPath; + + // Create the directory hierarchy + bfs::create_directories(target.parent_path()); + + bfs::file_status s = bfs::status(target.parent_path()); + if (!bfs::is_directory(s)) + { + std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl; + return 3; + } + + // Get a stream for the file to extract + // (inefficient because getFile iter on the list again) + Ogre::DataStreamPtr data = bsa.getFile(archivePath); + bfs::ofstream out(target, std::ios::binary); + + // Write the file to disk + std::cout << "Extracting " << target << std::endl; + out.write(data->getAsString().c_str(), data->size()); + out.close(); + } + return 0; } diff --git a/apps/bsatool/bsatool.ggo b/apps/bsatool/bsatool.ggo deleted file mode 100644 index 2e4227a1ba..0000000000 --- a/apps/bsatool/bsatool.ggo +++ /dev/null @@ -1,11 +0,0 @@ -package "bsatool" -version "1.0" -purpose "Inspect and extract files from Bethesda BSA archives" -#usage "" -#description "" -args "--unamed-opts=BSA-FILE -F bsatool_cmd -G" - -option "extract" x "Extract file from archive" string optional -option "long" l "Include extra information in archive listing" optional - -text "\nIf no option is given, the default action is to list all files in the archive." diff --git a/apps/bsatool/bsatool_cmd.c b/apps/bsatool/bsatool_cmd.c deleted file mode 100644 index 0b0ed66c2d..0000000000 --- a/apps/bsatool/bsatool_cmd.c +++ /dev/null @@ -1,1146 +0,0 @@ -/* - File autogenerated by gengetopt version 2.22.2 - generated with the following command: - gengetopt --unamed-opts=BSA-FILE -F bsatool_cmd -G - - The developers of gengetopt consider the fixed text that goes in all - gengetopt output files to be in the public domain: - we make no copyright claims on it. -*/ - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#ifndef FIX_UNUSED -#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ -#endif - - -#include "bsatool_cmd.h" - -const char *gengetopt_args_info_purpose = "Inspect and extract files from Bethesda BSA archives"; - -const char *gengetopt_args_info_usage = "Usage: bsatool [OPTIONS]... [BSA-FILE]..."; - -const char *gengetopt_args_info_description = ""; - -const char *gengetopt_args_info_help[] = { - " -h, --help Print help and exit", - " -V, --version Print version and exit", - " -x, --extract=STRING Extract file from archive", - " -l, --long Include extra information in archive listing", - "\nIf no option is given, the default action is to list all files in the archive.", - 0 -}; - -typedef enum {ARG_NO - , ARG_STRING -} cmdline_parser_arg_type; - -static -void clear_given (struct gengetopt_args_info *args_info); -static -void clear_args (struct gengetopt_args_info *args_info); - -static int -cmdline_parser_internal (int argc, char * const *argv, struct gengetopt_args_info *args_info, - struct cmdline_parser_params *params, const char *additional_error); - - -static char * -gengetopt_strdup (const char *s); - -static -void clear_given (struct gengetopt_args_info *args_info) -{ - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->extract_given = 0 ; - args_info->long_given = 0 ; -} - -static -void clear_args (struct gengetopt_args_info *args_info) -{ - FIX_UNUSED (args_info); - args_info->extract_arg = NULL; - args_info->extract_orig = NULL; - -} - -static -void init_args_info(struct gengetopt_args_info *args_info) -{ - - - args_info->help_help = gengetopt_args_info_help[0] ; - args_info->version_help = gengetopt_args_info_help[1] ; - args_info->extract_help = gengetopt_args_info_help[2] ; - args_info->long_help = gengetopt_args_info_help[3] ; - -} - -void -cmdline_parser_print_version (void) -{ - printf ("%s %s\n", - (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), - CMDLINE_PARSER_VERSION); -} - -static void print_help_common(void) { - cmdline_parser_print_version (); - - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); - - if (strlen(gengetopt_args_info_usage) > 0) - printf("\n%s\n", gengetopt_args_info_usage); - - printf("\n"); - - if (strlen(gengetopt_args_info_description) > 0) - printf("%s\n\n", gengetopt_args_info_description); -} - -void -cmdline_parser_print_help (void) -{ - int i = 0; - print_help_common(); - while (gengetopt_args_info_help[i]) - printf("%s\n", gengetopt_args_info_help[i++]); -} - -void -cmdline_parser_init (struct gengetopt_args_info *args_info) -{ - clear_given (args_info); - clear_args (args_info); - init_args_info (args_info); - - args_info->inputs = 0; - args_info->inputs_num = 0; -} - -void -cmdline_parser_params_init(struct cmdline_parser_params *params) -{ - if (params) - { - params->override = 0; - params->initialize = 1; - params->check_required = 1; - params->check_ambiguity = 0; - params->print_errors = 1; - } -} - -struct cmdline_parser_params * -cmdline_parser_params_create(void) -{ - struct cmdline_parser_params *params = - (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); - cmdline_parser_params_init(params); - return params; -} - -static void -free_string_field (char **s) -{ - if (*s) - { - free (*s); - *s = 0; - } -} - - -static void -cmdline_parser_release (struct gengetopt_args_info *args_info) -{ - unsigned int i; - free_string_field (&(args_info->extract_arg)); - free_string_field (&(args_info->extract_orig)); - - - for (i = 0; i < args_info->inputs_num; ++i) - free (args_info->inputs [i]); - - if (args_info->inputs_num) - free (args_info->inputs); - - clear_given (args_info); -} - - -static void -write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) -{ - FIX_UNUSED (values); - if (arg) { - fprintf(outfile, "%s=\"%s\"\n", opt, arg); - } else { - fprintf(outfile, "%s\n", opt); - } -} - - -int -cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) -{ - int i = 0; - - if (!outfile) - { - fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); - return EXIT_FAILURE; - } - - if (args_info->help_given) - write_into_file(outfile, "help", 0, 0 ); - if (args_info->version_given) - write_into_file(outfile, "version", 0, 0 ); - if (args_info->extract_given) - write_into_file(outfile, "extract", args_info->extract_orig, 0); - if (args_info->long_given) - write_into_file(outfile, "long", 0, 0 ); - - - i = EXIT_SUCCESS; - return i; -} - -int -cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) -{ - FILE *outfile; - int i = 0; - - outfile = fopen(filename, "w"); - - if (!outfile) - { - fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); - return EXIT_FAILURE; - } - - i = cmdline_parser_dump(outfile, args_info); - fclose (outfile); - - return i; -} - -void -cmdline_parser_free (struct gengetopt_args_info *args_info) -{ - cmdline_parser_release (args_info); -} - -/** @brief replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) -{ - char *result = 0; - if (!s) - return result; - - result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; -} - -int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) -{ - return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); -} - -int -cmdline_parser_ext (int argc, char * const *argv, struct gengetopt_args_info *args_info, - struct cmdline_parser_params *params) -{ - int result; - result = cmdline_parser_internal (argc, argv, args_info, params, 0); - - if (result == EXIT_FAILURE) - { - cmdline_parser_free (args_info); - exit (EXIT_FAILURE); - } - - return result; -} - -int -cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) -{ - int result; - struct cmdline_parser_params params; - - params.override = override; - params.initialize = initialize; - params.check_required = check_required; - params.check_ambiguity = 0; - params.print_errors = 1; - - result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); - - if (result == EXIT_FAILURE) - { - cmdline_parser_free (args_info); - exit (EXIT_FAILURE); - } - - return result; -} - -int -cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) -{ - FIX_UNUSED (args_info); - FIX_UNUSED (prog_name); - return EXIT_SUCCESS; -} - -/* - * Extracted from the glibc source tree, version 2.3.6 - * - * Licensed under the GPL as per the whole glibc source tree. - * - * This file was modified so that getopt_long can be called - * many times without risking previous memory to be spoiled. - * - * Modified by Andre Noll and Lorenzo Bettini for use in - * GNU gengetopt generated files. - * - */ - -/* - * we must include anything we need since this file is not thought to be - * inserted in a file already using getopt.h - * - * Lorenzo - */ - -struct option -{ - const char *name; - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. -*/ -/* - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `custom_optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -/* Names for the values of the `has_arg' field of `struct option'. */ -#ifndef no_argument -#define no_argument 0 -#endif - -#ifndef required_argument -#define required_argument 1 -#endif - -#ifndef optional_argument -#define optional_argument 2 -#endif - -struct custom_getopt_data { - /* - * These have exactly the same meaning as the corresponding global variables, - * except that they are used for the reentrant versions of getopt. - */ - int custom_optind; - int custom_opterr; - int custom_optopt; - char *custom_optarg; - - /* True if the internal members have been initialized. */ - int initialized; - - /* - * The next char to be scanned in the option-element in which the last option - * character we returned was found. This allows us to pick up the scan where - * we left off. If this is zero, or a null string, it means resume the scan by - * advancing to the next ARGV-element. - */ - char *nextchar; - - /* - * Describe the part of ARGV that contains non-options that have been skipped. - * `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is - * the index after the last of them. - */ - int first_nonopt; - int last_nonopt; -}; - -/* - * the variables optarg, optind, opterr and optopt are renamed with - * the custom_ prefix so that they don't interfere with getopt ones. - * - * Moreover they're static so they are visible only from within the - * file where this very file will be included. - */ - -/* - * For communication from `custom_getopt' to the caller. When `custom_getopt' finds an - * option that takes an argument, the argument value is returned here. - */ -static char *custom_optarg; - -/* - * Index in ARGV of the next element to be scanned. This is used for - * communication to and from the caller and for communication between - * successive calls to `custom_getopt'. - * - * On entry to `custom_getopt', 1 means this is the first call; initialize. - * - * When `custom_getopt' returns -1, this is the index of the first of the non-option - * elements that the caller should itself scan. - * - * Otherwise, `custom_optind' communicates from one call to the next how much of ARGV - * has been scanned so far. - * - * 1003.2 says this must be 1 before any call. - */ -static int custom_optind = 1; - -/* - * Callers store zero here to inhibit the error message for unrecognized - * options. - */ -static int custom_opterr = 1; - -/* - * Set to an option character which was unrecognized. This must be initialized - * on some systems to avoid linking in the system's own getopt implementation. - */ -static int custom_optopt = '?'; - -/* - * Exchange two adjacent subsequences of ARGV. One subsequence is elements - * [first_nonopt,last_nonopt) which contains all the non-options that have been - * skipped so far. The other is elements [last_nonopt,custom_optind), which contains - * all the options processed since those non-options were skipped. - * `first_nonopt' and `last_nonopt' are relocated so that they describe the new - * indices of the non-options in ARGV after they are moved. - */ -static void exchange(char **argv, struct custom_getopt_data *d) -{ - int bottom = d->first_nonopt; - int middle = d->last_nonopt; - int top = d->custom_optind; - char *tem; - - /* - * Exchange the shorter segment with the far end of the longer segment. - * That puts the shorter segment into the right place. It leaves the - * longer segment in the right place overall, but it consists of two - * parts that need to be swapped next. - */ - while (top > middle && middle > bottom) { - if (top - middle > middle - bottom) { - /* Bottom segment is the short one. */ - int len = middle - bottom; - int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) { - tem = argv[bottom + i]; - argv[bottom + i] = - argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } else { - /* Top segment is the short one. */ - int len = top - middle; - int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - /* Update records for the slots the non-options now occupy. */ - d->first_nonopt += (d->custom_optind - d->last_nonopt); - d->last_nonopt = d->custom_optind; -} - -/* Initialize the internal data when the first call is made. */ -static void custom_getopt_initialize(struct custom_getopt_data *d) -{ - /* - * Start processing options with ARGV-element 1 (since ARGV-element 0 - * is the program name); the sequence of previously skipped non-option - * ARGV-elements is empty. - */ - d->first_nonopt = d->last_nonopt = d->custom_optind; - d->nextchar = NULL; - d->initialized = 1; -} - -#define NONOPTION_P (argv[d->custom_optind][0] != '-' || argv[d->custom_optind][1] == '\0') - -/* return: zero: continue, nonzero: return given value to user */ -static int shuffle_argv(int argc, char *const *argv,const struct option *longopts, - struct custom_getopt_data *d) -{ - /* - * Give FIRST_NONOPT & LAST_NONOPT rational values if CUSTOM_OPTIND has been - * moved back by the user (who may also have changed the arguments). - */ - if (d->last_nonopt > d->custom_optind) - d->last_nonopt = d->custom_optind; - if (d->first_nonopt > d->custom_optind) - d->first_nonopt = d->custom_optind; - /* - * If we have just processed some options following some - * non-options, exchange them so that the options come first. - */ - if (d->first_nonopt != d->last_nonopt && - d->last_nonopt != d->custom_optind) - exchange((char **) argv, d); - else if (d->last_nonopt != d->custom_optind) - d->first_nonopt = d->custom_optind; - /* - * Skip any additional non-options and extend the range of - * non-options previously skipped. - */ - while (d->custom_optind < argc && NONOPTION_P) - d->custom_optind++; - d->last_nonopt = d->custom_optind; - /* - * The special ARGV-element `--' means premature end of options. Skip - * it like a null option, then exchange with previous non-options as if - * it were an option, then skip everything else like a non-option. - */ - if (d->custom_optind != argc && !strcmp(argv[d->custom_optind], "--")) { - d->custom_optind++; - if (d->first_nonopt != d->last_nonopt - && d->last_nonopt != d->custom_optind) - exchange((char **) argv, d); - else if (d->first_nonopt == d->last_nonopt) - d->first_nonopt = d->custom_optind; - d->last_nonopt = argc; - d->custom_optind = argc; - } - /* - * If we have done all the ARGV-elements, stop the scan and back over - * any non-options that we skipped and permuted. - */ - if (d->custom_optind == argc) { - /* - * Set the next-arg-index to point at the non-options that we - * previously skipped, so the caller will digest them. - */ - if (d->first_nonopt != d->last_nonopt) - d->custom_optind = d->first_nonopt; - return -1; - } - /* - * If we have come to a non-option and did not permute it, either stop - * the scan or describe it to the caller and pass it by. - */ - if (NONOPTION_P) { - d->custom_optarg = argv[d->custom_optind++]; - return 1; - } - /* - * We have found another option-ARGV-element. Skip the initial - * punctuation. - */ - d->nextchar = (argv[d->custom_optind] + 1 + (longopts != NULL && argv[d->custom_optind][1] == '-')); - return 0; -} - -/* - * Check whether the ARGV-element is a long option. - * - * If there's a long option "fubar" and the ARGV-element is "-fu", consider - * that an abbreviation of the long option, just like "--fu", and not "-f" with - * arg "u". - * - * This distinction seems to be the most useful approach. - * - */ -static int check_long_opt(int argc, char *const *argv, const char *optstring, - const struct option *longopts, int *longind, - int print_errors, struct custom_getopt_data *d) -{ - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = d->nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match or abbreviated matches */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp(p->name, d->nextchar, nameend - d->nextchar)) { - if ((unsigned int) (nameend - d->nextchar) - == (unsigned int) strlen(p->name)) { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } else if (pfound == NULL) { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } else if (pfound->has_arg != p->has_arg - || pfound->flag != p->flag - || pfound->val != p->val) - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) { - if (print_errors) { - fprintf(stderr, - "%s: option `%s' is ambiguous\n", - argv[0], argv[d->custom_optind]); - } - d->nextchar += strlen(d->nextchar); - d->custom_optind++; - d->custom_optopt = 0; - return '?'; - } - if (pfound) { - option_index = indfound; - d->custom_optind++; - if (*nameend) { - if (pfound->has_arg != no_argument) - d->custom_optarg = nameend + 1; - else { - if (print_errors) { - if (argv[d->custom_optind - 1][1] == '-') { - /* --option */ - fprintf(stderr, "%s: option `--%s' doesn't allow an argument\n", - argv[0], pfound->name); - } else { - /* +option or -option */ - fprintf(stderr, "%s: option `%c%s' doesn't allow an argument\n", - argv[0], argv[d->custom_optind - 1][0], pfound->name); - } - - } - d->nextchar += strlen(d->nextchar); - d->custom_optopt = pfound->val; - return '?'; - } - } else if (pfound->has_arg == required_argument) { - if (d->custom_optind < argc) - d->custom_optarg = argv[d->custom_optind++]; - else { - if (print_errors) { - fprintf(stderr, - "%s: option `%s' requires an argument\n", - argv[0], - argv[d->custom_optind - 1]); - } - d->nextchar += strlen(d->nextchar); - d->custom_optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - d->nextchar += strlen(d->nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - /* - * Can't find it as a long option. If this is not getopt_long_only, or - * the option starts with '--' or is not a valid short option, then - * it's an error. Otherwise interpret it as a short option. - */ - if (print_errors) { - if (argv[d->custom_optind][1] == '-') { - /* --option */ - fprintf(stderr, - "%s: unrecognized option `--%s'\n", - argv[0], d->nextchar); - } else { - /* +option or -option */ - fprintf(stderr, - "%s: unrecognized option `%c%s'\n", - argv[0], argv[d->custom_optind][0], - d->nextchar); - } - } - d->nextchar = (char *) ""; - d->custom_optind++; - d->custom_optopt = 0; - return '?'; -} - -static int check_short_opt(int argc, char *const *argv, const char *optstring, - int print_errors, struct custom_getopt_data *d) -{ - char c = *d->nextchar++; - const char *temp = strchr(optstring, c); - - /* Increment `custom_optind' when we start to process its last character. */ - if (*d->nextchar == '\0') - ++d->custom_optind; - if (!temp || c == ':') { - if (print_errors) - fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); - - d->custom_optopt = c; - return '?'; - } - if (temp[1] == ':') { - if (temp[2] == ':') { - /* This is an option that accepts an argument optionally. */ - if (*d->nextchar != '\0') { - d->custom_optarg = d->nextchar; - d->custom_optind++; - } else - d->custom_optarg = NULL; - d->nextchar = NULL; - } else { - /* This is an option that requires an argument. */ - if (*d->nextchar != '\0') { - d->custom_optarg = d->nextchar; - /* - * If we end this ARGV-element by taking the - * rest as an arg, we must advance to the next - * element now. - */ - d->custom_optind++; - } else if (d->custom_optind == argc) { - if (print_errors) { - fprintf(stderr, - "%s: option requires an argument -- %c\n", - argv[0], c); - } - d->custom_optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } else - /* - * We already incremented `custom_optind' once; - * increment it again when taking next ARGV-elt - * as argument. - */ - d->custom_optarg = argv[d->custom_optind++]; - d->nextchar = NULL; - } - } - return c; -} - -/* - * Scan elements of ARGV for option characters given in OPTSTRING. - * - * If an element of ARGV starts with '-', and is not exactly "-" or "--", - * then it is an option element. The characters of this element - * (aside from the initial '-') are option characters. If `getopt' - * is called repeatedly, it returns successively each of the option characters - * from each of the option elements. - * - * If `getopt' finds another option character, it returns that character, - * updating `custom_optind' and `nextchar' so that the next call to `getopt' can - * resume the scan with the following option character or ARGV-element. - * - * If there are no more option characters, `getopt' returns -1. - * Then `custom_optind' is the index in ARGV of the first ARGV-element - * that is not an option. (The ARGV-elements have been permuted - * so that those that are not options now come last.) - * - * OPTSTRING is a string containing the legitimate option characters. - * If an option character is seen that is not listed in OPTSTRING, - * return '?' after printing an error message. If you set `custom_opterr' to - * zero, the error message is suppressed but we still return '?'. - * - * If a char in OPTSTRING is followed by a colon, that means it wants an arg, - * so the following text in the same ARGV-element, or the text of the following - * ARGV-element, is returned in `custom_optarg'. Two colons mean an option that - * wants an optional arg; if there is text in the current ARGV-element, - * it is returned in `custom_optarg', otherwise `custom_optarg' is set to zero. - * - * If OPTSTRING starts with `-' or `+', it requests different methods of - * handling the non-option ARGV-elements. - * See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - * - * Long-named options begin with `--' instead of `-'. - * Their names may be abbreviated as long as the abbreviation is unique - * or is an exact match for some defined option. If they have an - * argument, it follows the option name in the same ARGV-element, separated - * from the option name by a `=', or else the in next ARGV-element. - * When `getopt' finds a long-named option, it returns 0 if that option's - * `flag' field is nonzero, the value of the option's `val' field - * if the `flag' field is zero. - * - * The elements of ARGV aren't really const, because we permute them. - * But we pretend they're const in the prototype to be compatible - * with other systems. - * - * LONGOPTS is a vector of `struct option' terminated by an - * element containing a name which is zero. - * - * LONGIND returns the index in LONGOPT of the long-named option found. - * It is only valid when a long-named option has been found by the most - * recent call. - * - * Return the option character from OPTS just read. Return -1 when there are - * no more options. For unrecognized options, or options missing arguments, - * `custom_optopt' is set to the option letter, and '?' is returned. - * - * The OPTS string is a list of characters which are recognized option letters, - * optionally followed by colons, specifying that that letter takes an - * argument, to be placed in `custom_optarg'. - * - * If a letter in OPTS is followed by two colons, its argument is optional. - * This behavior is specific to the GNU `getopt'. - * - * The argument `--' causes premature termination of argument scanning, - * explicitly telling `getopt' that there are no more options. If OPTS begins - * with `--', then non-option arguments are treated as arguments to the option - * '\0'. This behavior is specific to the GNU `getopt'. - */ - -static int getopt_internal_r(int argc, char *const *argv, const char *optstring, - const struct option *longopts, int *longind, - struct custom_getopt_data *d) -{ - int ret, print_errors = d->custom_opterr; - - if (optstring[0] == ':') - print_errors = 0; - if (argc < 1) - return -1; - d->custom_optarg = NULL; - - /* - * This is a big difference with GNU getopt, since optind == 0 - * means initialization while here 1 means first call. - */ - if (d->custom_optind == 0 || !d->initialized) { - if (d->custom_optind == 0) - d->custom_optind = 1; /* Don't scan ARGV[0], the program name. */ - custom_getopt_initialize(d); - } - if (d->nextchar == NULL || *d->nextchar == '\0') { - ret = shuffle_argv(argc, argv, longopts, d); - if (ret) - return ret; - } - if (longopts && (argv[d->custom_optind][1] == '-' )) - return check_long_opt(argc, argv, optstring, longopts, - longind, print_errors, d); - return check_short_opt(argc, argv, optstring, print_errors, d); -} - -static int custom_getopt_internal(int argc, char *const *argv, const char *optstring, - const struct option *longopts, int *longind) -{ - int result; - /* Keep a global copy of all internal members of d */ - static struct custom_getopt_data d; - - d.custom_optind = custom_optind; - d.custom_opterr = custom_opterr; - result = getopt_internal_r(argc, argv, optstring, longopts, - longind, &d); - custom_optind = d.custom_optind; - custom_optarg = d.custom_optarg; - custom_optopt = d.custom_optopt; - return result; -} - -static int custom_getopt_long (int argc, char *const *argv, const char *options, - const struct option *long_options, int *opt_index) -{ - return custom_getopt_internal(argc, argv, options, long_options, - opt_index); -} - - -static char *package_name = 0; - -/** - * @brief updates an option - * @param field the generic pointer to the field to update - * @param orig_field the pointer to the orig field - * @param field_given the pointer to the number of occurrence of this option - * @param prev_given the pointer to the number of occurrence already seen - * @param value the argument for this option (if null no arg was specified) - * @param possible_values the possible values for this option (if specified) - * @param default_value the default value (in case the option only accepts fixed values) - * @param arg_type the type of this option - * @param check_ambiguity @see cmdline_parser_params.check_ambiguity - * @param override @see cmdline_parser_params.override - * @param no_free whether to free a possible previous value - * @param multiple_option whether this is a multiple option - * @param long_opt the corresponding long option - * @param short_opt the corresponding short option (or '-' if none) - * @param additional_error possible further error specification - */ -static -int update_arg(void *field, char **orig_field, - unsigned int *field_given, unsigned int *prev_given, - char *value, const char *possible_values[], - const char *default_value, - cmdline_parser_arg_type arg_type, - int check_ambiguity, int override, - int no_free, int multiple_option, - const char *long_opt, char short_opt, - const char *additional_error) -{ - FIX_UNUSED (field); - char *stop_char = 0; - const char *val = value; - int found; - char **string_field; - - stop_char = 0; - found = 0; - - if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) - { - if (short_opt != '-') - fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", - package_name, long_opt, short_opt, - (additional_error ? additional_error : "")); - else - fprintf (stderr, "%s: `--%s' option given more than once%s\n", - package_name, long_opt, - (additional_error ? additional_error : "")); - return 1; /* failure */ - } - - FIX_UNUSED (default_value); - - if (field_given && *field_given && ! override) - return 0; - if (prev_given) - (*prev_given)++; - if (field_given) - (*field_given)++; - if (possible_values) - val = possible_values[found]; - - switch(arg_type) { - case ARG_STRING: - if (val) { - string_field = (char **)field; - if (!no_free && *string_field) - free (*string_field); /* free previous string */ - *string_field = gengetopt_strdup (val); - } - break; - default: - break; - }; - - - /* store the original value */ - switch(arg_type) { - case ARG_NO: - break; - default: - if (value && orig_field) { - if (no_free) { - *orig_field = value; - } else { - if (*orig_field) - free (*orig_field); /* free previous string */ - *orig_field = gengetopt_strdup (value); - } - } - }; - - return 0; /* OK */ -} - - -int -cmdline_parser_internal ( - int argc, char * const *argv, struct gengetopt_args_info *args_info, - struct cmdline_parser_params *params, const char *additional_error) -{ - int c; /* Character of the parsed option. */ - - int error = 0; - struct gengetopt_args_info local_args_info; - - int override; - int initialize; - int check_required; - int check_ambiguity; - - char *optarg; - int optind; - int opterr; - int optopt; - - package_name = argv[0]; - - override = params->override; - initialize = params->initialize; - check_required = params->check_required; - check_ambiguity = params->check_ambiguity; - - if (initialize) - cmdline_parser_init (args_info); - - cmdline_parser_init (&local_args_info); - - optarg = 0; - optind = 0; - opterr = params->print_errors; - optopt = '?'; - - while (1) - { - int option_index = 0; - - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "extract", 1, NULL, 'x' }, - { "long", 0, NULL, 'l' }, - { 0, 0, 0, 0 } - }; - - custom_optarg = optarg; - custom_optind = optind; - custom_opterr = opterr; - custom_optopt = optopt; - - c = custom_getopt_long (argc, argv, "hVx:l", long_options, &option_index); - - optarg = custom_optarg; - optind = custom_optind; - opterr = custom_opterr; - optopt = custom_optopt; - - if (c == -1) break; /* Exit from `while (1)' loop. */ - - switch (c) - { - case 'h': /* Print help and exit. */ - cmdline_parser_print_help (); - cmdline_parser_free (&local_args_info); - exit (EXIT_SUCCESS); - - case 'V': /* Print version and exit. */ - cmdline_parser_print_version (); - cmdline_parser_free (&local_args_info); - exit (EXIT_SUCCESS); - - case 'x': /* Extract file from archive. */ - - - if (update_arg( (void *)&(args_info->extract_arg), - &(args_info->extract_orig), &(args_info->extract_given), - &(local_args_info.extract_given), optarg, 0, 0, ARG_STRING, - check_ambiguity, override, 0, 0, - "extract", 'x', - additional_error)) - goto failure; - - break; - case 'l': /* Include extra information in archive listing. */ - - - if (update_arg( 0 , - 0 , &(args_info->long_given), - &(local_args_info.long_given), optarg, 0, 0, ARG_NO, - check_ambiguity, override, 0, 0, - "long", 'l', - additional_error)) - goto failure; - - break; - - case 0: /* Long option with no short option */ - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - goto failure; - - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); - abort (); - } /* switch */ - } /* while */ - - - - - cmdline_parser_release (&local_args_info); - - if ( error ) - return (EXIT_FAILURE); - - if (optind < argc) - { - int i = 0 ; - int found_prog_name = 0; - /* whether program name, i.e., argv[0], is in the remaining args - (this may happen with some implementations of getopt, - but surely not with the one included by gengetopt) */ - - - args_info->inputs_num = argc - optind - found_prog_name; - args_info->inputs = - (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ; - while (optind < argc) - args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind++]) ; - } - - return 0; - -failure: - - cmdline_parser_release (&local_args_info); - return (EXIT_FAILURE); -} diff --git a/apps/bsatool/bsatool_cmd.h b/apps/bsatool/bsatool_cmd.h deleted file mode 100644 index 4d5f80ea27..0000000000 --- a/apps/bsatool/bsatool_cmd.h +++ /dev/null @@ -1,179 +0,0 @@ -/** @file bsatool_cmd.h - * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.2 - * http://www.gnu.org/software/gengetopt. - * DO NOT modify this file, since it can be overwritten - * @author GNU Gengetopt by Lorenzo Bettini */ - -#ifndef BSATOOL_CMD_H -#define BSATOOL_CMD_H - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include /* for FILE */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef CMDLINE_PARSER_PACKAGE -/** @brief the program name (used for printing errors) */ -#define CMDLINE_PARSER_PACKAGE "bsatool" -#endif - -#ifndef CMDLINE_PARSER_PACKAGE_NAME -/** @brief the complete program name (used for help and version) */ -#define CMDLINE_PARSER_PACKAGE_NAME "bsatool" -#endif - -#ifndef CMDLINE_PARSER_VERSION -/** @brief the program version */ -#define CMDLINE_PARSER_VERSION "1.0" -#endif - -/** @brief Where the command line options are stored */ -struct gengetopt_args_info -{ - const char *help_help; /**< @brief Print help and exit help description. */ - const char *version_help; /**< @brief Print version and exit help description. */ - char * extract_arg; /**< @brief Extract file from archive. */ - char * extract_orig; /**< @brief Extract file from archive original value given at command line. */ - const char *extract_help; /**< @brief Extract file from archive help description. */ - const char *long_help; /**< @brief Include extra information in archive listing help description. */ - - unsigned int help_given ; /**< @brief Whether help was given. */ - unsigned int version_given ; /**< @brief Whether version was given. */ - unsigned int extract_given ; /**< @brief Whether extract was given. */ - unsigned int long_given ; /**< @brief Whether long was given. */ - - char **inputs ; /**< @brief unamed options (options without names) */ - unsigned inputs_num ; /**< @brief unamed options number */ -} ; - -/** @brief The additional parameters to pass to parser functions */ -struct cmdline_parser_params -{ - int override; /**< @brief whether to override possibly already present options (default 0) */ - int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ - int check_required; /**< @brief whether to check that all required options were provided (default 1) */ - int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ - int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ -} ; - -/** @brief the purpose string of the program */ -extern const char *gengetopt_args_info_purpose; -/** @brief the usage string of the program */ -extern const char *gengetopt_args_info_usage; -/** @brief all the lines making the help output */ -extern const char *gengetopt_args_info_help[]; - -/** - * The command line parser - * @param argc the number of command line options - * @param argv the command line options - * @param args_info the structure where option information will be stored - * @return 0 if everything went fine, NON 0 if an error took place - */ -int cmdline_parser (int argc, char * const *argv, - struct gengetopt_args_info *args_info); - -/** - * The command line parser (version with additional parameters - deprecated) - * @param argc the number of command line options - * @param argv the command line options - * @param args_info the structure where option information will be stored - * @param override whether to override possibly already present options - * @param initialize whether to initialize the option structure my_args_info - * @param check_required whether to check that all required options were provided - * @return 0 if everything went fine, NON 0 if an error took place - * @deprecated use cmdline_parser_ext() instead - */ -int cmdline_parser2 (int argc, char * const *argv, - struct gengetopt_args_info *args_info, - int override, int initialize, int check_required); - -/** - * The command line parser (version with additional parameters) - * @param argc the number of command line options - * @param argv the command line options - * @param args_info the structure where option information will be stored - * @param params additional parameters for the parser - * @return 0 if everything went fine, NON 0 if an error took place - */ -int cmdline_parser_ext (int argc, char * const *argv, - struct gengetopt_args_info *args_info, - struct cmdline_parser_params *params); - -/** - * Save the contents of the option struct into an already open FILE stream. - * @param outfile the stream where to dump options - * @param args_info the option struct to dump - * @return 0 if everything went fine, NON 0 if an error took place - */ -int cmdline_parser_dump(FILE *outfile, - struct gengetopt_args_info *args_info); - -/** - * Save the contents of the option struct into a (text) file. - * This file can be read by the config file parser (if generated by gengetopt) - * @param filename the file where to save - * @param args_info the option struct to save - * @return 0 if everything went fine, NON 0 if an error took place - */ -int cmdline_parser_file_save(const char *filename, - struct gengetopt_args_info *args_info); - -/** - * Print the help - */ -void cmdline_parser_print_help(void); -/** - * Print the version - */ -void cmdline_parser_print_version(void); - -/** - * Initializes all the fields a cmdline_parser_params structure - * to their default values - * @param params the structure to initialize - */ -void cmdline_parser_params_init(struct cmdline_parser_params *params); - -/** - * Allocates dynamically a cmdline_parser_params structure and initializes - * all its fields to their default values - * @return the created and initialized cmdline_parser_params structure - */ -struct cmdline_parser_params *cmdline_parser_params_create(void); - -/** - * Initializes the passed gengetopt_args_info structure's fields - * (also set default values for options that have a default) - * @param args_info the structure to initialize - */ -void cmdline_parser_init (struct gengetopt_args_info *args_info); -/** - * Deallocates the string fields of the gengetopt_args_info structure - * (but does not deallocate the structure itself) - * @param args_info the structure to deallocate - */ -void cmdline_parser_free (struct gengetopt_args_info *args_info); - -/** - * Checks that all the required options were specified - * @param args_info the structure to check - * @param prog_name the name of the program that will be used to print - * possible errors - * @return - */ -int cmdline_parser_required (struct gengetopt_args_info *args_info, - const char *prog_name); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* BSATOOL_CMD_H */ From d696da767762739af746c255a45c1a8040950225 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Mar 2013 21:38:27 +0100 Subject: [PATCH 0633/1483] Fix selection buffer --- libs/openengine/ogre/selectionbuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index c6b43a45de..30e7b9e1e5 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -24,7 +24,8 @@ namespace Render vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); vp->setShadowsEnabled(false); vp->setMaterialScheme("selectionbuffer"); - vp->setVisibilityMask (visibilityFlags); + if (visibilityFlags != 0) + vp->setVisibilityMask (visibilityFlags); mRenderTarget->setActive(true); mRenderTarget->setAutoUpdated (false); From 285b4bf726448722a2390260280925600b23c56f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 Mar 2013 00:12:56 +0100 Subject: [PATCH 0634/1483] Allow zooming camera in vanity or preview mode with the mousewheel --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ apps/openmw/mwrender/player.cpp | 7 +++++++ apps/openmw/mwrender/player.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.hpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 4 ++++ 6 files changed, 22 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 654a59cea8..6cd5b90b40 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -296,6 +296,7 @@ namespace MWBase virtual bool toggleVanityMode(bool enable, bool force) = 0; virtual void allowVanityMode(bool allow) = 0; virtual void togglePlayerLooking(bool enable) = 0; + virtual void changeVanityModeScale(float factor) = 0; virtual void renderPlayer() = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4c10749b32..f18c02a0e8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -548,6 +548,9 @@ namespace MWInput MWBase::World *world = MWBase::Environment::get().getWorld(); world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); + + if (arg.state.Z.rel) + MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); } return true; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 1ac3b072f5..63396378d0 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -271,6 +271,8 @@ namespace MWRender v.z = 800.f; } else if (v.z < 10.f) { v.z = 10.f; + } else if (override && v.z < 50.f) { + v.z = 50.f; } mCamera->setPosition(v); @@ -362,4 +364,9 @@ namespace MWRender mCameraNode->setPosition(0.f, 0.f, mHeight); } } + + bool Player::isVanityOrPreviewModeEnabled() + { + return mPreviewMode || mVanity.enabled; + } } diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index e24f44d68a..9de41823de 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -110,6 +110,8 @@ namespace MWRender void getSightAngles(float &pitch, float &yaw); void togglePlayerLooking(bool enable); + + bool isVanityOrPreviewModeEnabled(); }; } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5cea241754..1777a72c33 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -83,6 +83,11 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList mPlayer->togglePlayerLooking(enable); } + void changeVanityModeScale(float factor) { + if (mPlayer->isVanityOrPreviewModeEnabled()) + mPlayer->setCameraDistance(-factor/120.f*10, true, true); + } + void getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw); void attachCameraTo(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 47088aa62c..fe4ceff692 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -339,6 +339,10 @@ namespace MWWorld mRendering->togglePlayerLooking(enable); } + virtual void changeVanityModeScale(float factor) { + mRendering->changeVanityModeScale(factor); + } + virtual void renderPlayer(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); From 03c7f181125e05ebf8a46818f9e616db9a267db7 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Wed, 6 Mar 2013 06:41:33 -0600 Subject: [PATCH 0635/1483] Fixes for save-on-close message boxes --- apps/opencs/CMakeLists.txt | 1 - apps/opencs/model/doc/document.cpp | 7 +- apps/opencs/view/doc/view.cpp | 19 ++-- apps/opencs/view/doc/view.hpp | 10 +- apps/opencs/view/doc/viewmanager.cpp | 156 ++++++++++++++++++--------- apps/opencs/view/doc/viewmanager.hpp | 17 ++- 6 files changed, 141 insertions(+), 69 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d5d389a141..0446d921ff 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -1,4 +1,3 @@ - set (OPENCS_SRC main.cpp) opencs_units (. editor) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index b361577bec..2cdd1f5383 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -287,11 +287,13 @@ void CSMDoc::Document::abortOperation (int type) } } + void CSMDoc::Document::modificationStateChanged (bool clean) { emit stateChanged (getState(), this); } + void CSMDoc::Document::operationDone (int type) { emit stateChanged (getState(), this); @@ -305,9 +307,12 @@ void CSMDoc::Document::saving() if (mSaveCount>15) { + //clear the stack before resetting the save state + //to avoid emitting incorrect states + mUndoStack.setClean(); + mSaveCount = 0; mSaveTimer.stop(); - mUndoStack.setClean(); emit stateChanged (getState(), this); } } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 78eba78801..29aa471fdf 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -46,10 +46,10 @@ void CSVDoc::View::setupFileMenu() file->addAction(close); QAction *exit = new QAction (tr ("&Exit"), this); - connect (exit, SIGNAL (triggered()), QApplication::instance(), SLOT (closeAllWindows())); + connect (exit, SIGNAL (triggered()), this, SLOT (exitApplication())); + connect (this, SIGNAL (closeAllViews(View *)), &mViewManager, SLOT (closeAllViews(View *))); + file->addAction(exit); - - } void CSVDoc::View::setupEditMenu() @@ -132,13 +132,11 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - setAttribute (Qt::WA_DeleteOnClose, true); setDockOptions (QMainWindow::AllowNestedDocks); resize (300, 300); /// \todo get default size from settings and set reasonable minimal size - mSubViewWindow = new QMainWindow(); - setCentralWidget (mSubViewWindow); + setCentralWidget (&mSubViewWindow); mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); @@ -213,7 +211,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) SubView *view = mSubViewFactory.makeSubView (id, *mDocument); - mSubViewWindow->addDockWidget (Qt::TopDockWidgetArea, view); + mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, SLOT (addSubView (const CSMWorld::UniversalId&))); @@ -252,7 +250,12 @@ void CSVDoc::View::abortOperation (int type) updateActions(); } -QDockWidget *CSVDoc::View::getOperations() const +CSVDoc::Operations *CSVDoc::View::getOperations() const { return mOperations; } + +void CSVDoc::View::exitApplication() +{ + emit closeAllViews (this); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index d436aebe76..d6b6ad4601 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -41,7 +41,8 @@ namespace CSVDoc std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; - QMainWindow* mSubViewWindow; + QMainWindow mSubViewWindow; + // not implemented View (const View&); @@ -68,6 +69,7 @@ namespace CSVDoc public: View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); + ///< The ownership of \a document is not transferred to *this. virtual ~View(); @@ -82,7 +84,7 @@ namespace CSVDoc void updateProgress (int current, int max, int type, int threads); - QDockWidget *getOperations() const; + Operations *getOperations() const; signals: @@ -90,6 +92,8 @@ namespace CSVDoc void loadDocumentRequest(); + void closeAllViews (View *); + public slots: void addSubView (const CSMWorld::UniversalId& id); @@ -108,6 +112,8 @@ namespace CSVDoc void addGmstsSubView(); + void exitApplication(); + }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 63dd18291c..9bb96167d9 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -13,7 +13,7 @@ #include "view.hpp" #include - +#include void CSVDoc::ViewManager::updateIndices() { @@ -34,7 +34,7 @@ void CSVDoc::ViewManager::updateIndices() } CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) - : mDocumentManager (documentManager), mCloseMeOnSaveStateChange(0) + : mDocumentManager (documentManager), mCloseMeOnSaveStateChange(0), mUserWarned(false) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; @@ -46,6 +46,7 @@ CSVDoc::ViewManager::~ViewManager() { delete mDelegateFactories; + //not needed due to deletion in ViewManager::closeRequest? for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; } @@ -64,6 +65,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) View *view = new View (*this, document, countViews (document)+1); + mViews.push_back (view); view->show(); @@ -106,17 +108,18 @@ bool CSVDoc::ViewManager::closeRequest (View *view) { //notify user of saving in progress if ( (document->getState() & CSMDoc::State_Saving) ) - continueWithClose = showSaveInProgressMessageBox (view); - else - //notify user of unsaved changes and process response - if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (view); - } + continueWithClose = showSaveInProgressMessageBox (iter); - mViews.erase (iter); + //notify user of unsaved changes and process response + else if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (iter); + } if (continueWithClose) { + (*iter)->deleteLater(); + mViews.erase (iter); + if (last) mDocumentManager.removeDocument (document); else @@ -127,7 +130,7 @@ bool CSVDoc::ViewManager::closeRequest (View *view) return continueWithClose; } -bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) +bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::iterator viewIter) { QMessageBox messageBox; @@ -138,23 +141,32 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) bool retVal = true; - switch (messageBox.exec()) + connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); + connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + mUserWarned = true; + + int response = messageBox.exec(); + + mUserWarned = false; + + switch (response) { case QMessageBox::Save: - view->getDocument()->save(); - retVal = !(view->getDocument()->getState() & CSMDoc::State_Saving); - - if (!retVal) - mCloseMeOnSaveStateChange = view; - else - mCloseMeOnSaveStateChange = 0; + (*viewIter)->getDocument()->save(); + mCloseMeOnSaveStateChange = viewIter; + retVal = false; break; case QMessageBox::Discard: + + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); break; case QMessageBox::Cancel: + + //disconnect to prevent unintended view closures + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); retVal = false; break; @@ -166,43 +178,55 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) return retVal; } -bool CSVDoc::ViewManager::showSaveInProgressMessageBox (View* view) +bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::iterator viewIter) { QMessageBox messageBox; messageBox.setText ("The document is currently being saved."); - messageBox.setInformativeText("Do you want to abort the save?"); - messageBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + messageBox.setInformativeText("Do you want to close now and abort saving, or wait until saving has completed?"); + + QPushButton* waitButton = messageBox.addButton (tr("Wait"), QMessageBox::YesRole); + QPushButton* closeButton = messageBox.addButton (tr("Close Now"), QMessageBox::RejectRole); + QPushButton* cancelButton = messageBox.addButton (tr("Cancel"), QMessageBox::NoRole); + + messageBox.setDefaultButton (waitButton); bool retVal = true; - switch (messageBox.exec()) + //Connections shut down message box if operation ends before user makes a decision. + connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); + + //set / clear the user warned flag to indicate whether or not the message box is currently active. + mUserWarned = true; + + messageBox.exec(); + + mUserWarned = false; + + //if closed by the warning handler, defaults to the RejectRole button (closeButton) + if (messageBox.clickedButton() == waitButton) { - case QMessageBox::Yes: //immediate shutdown - mCloseMeOnSaveStateChange = 0; - view->abortOperation(CSMDoc::State_Saving); - break; + //save the View iterator for shutdown after the save operation ends + mCloseMeOnSaveStateChange = viewIter; + retVal = false; + } - case QMessageBox::No: //shutdown after save completes + else if (messageBox.clickedButton() == closeButton) + { + //disconnect to avoid segmentation fault + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + (*viewIter)->abortOperation(CSMDoc::State_Saving); + mCloseMeOnSaveStateChange = mViews.end(); + } - //return true (continue with close) if the save operation ended before the - //user clicked "No" - retVal = !(view->getDocument()->getState() & CSMDoc::State_Saving); - - if (!retVal) - mCloseMeOnSaveStateChange = view; - else - mCloseMeOnSaveStateChange = 0; - - break; - - case QMessageBox::Cancel: //abort shutdown, allow save to complete - mCloseMeOnSaveStateChange = 0; - retVal = false; - break; - - default: - break; + else if (messageBox.clickedButton() == cancelButton) + { + //abort shutdown, allow save to complete + //disconnection to prevent unintended view closures + mCloseMeOnSaveStateChange = mViews.end(); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + retVal = false; } return retVal; @@ -213,13 +237,6 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) (*iter)->updateDocumentState(); - - //mechanism to shutdown main window after saving operation completes - if (mCloseMeOnSaveStateChange && (mPreviousDocumentState & CSMDoc::State_Saving)) - if (mCloseMeOnSaveStateChange->close()) - mCloseMeOnSaveStateChange = 0; - - mPreviousDocumentState = state; } void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, CSMDoc::Document *document) @@ -228,3 +245,38 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, if ((*iter)->getDocument()==document) (*iter)->updateProgress (current, max, type, threads); } + +void CSVDoc::ViewManager::onCloseWarningHandler (int state, CSMDoc::Document *document) +{ + if ( !(state & CSMDoc::State_Saving) ) + { + //if the user is being warned (message box is active), shut down the message box, + //as there is no save operation currently running + if ( mUserWarned ) + emit closeMessageBox(); + + //otherwise, the user has closed the message box before the save operation ended. + //close the view + else if (mCloseMeOnSaveStateChange!=mViews.end()) + { + (*mCloseMeOnSaveStateChange)->close(); + mCloseMeOnSaveStateChange = mViews.end(); + } + } +} + +void CSVDoc::ViewManager::closeAllViews (View *lastView) +{ + //forces document views to close in an orderly manner + // the last view closed is the view from which the "Exit" action was triggered + while (mViews.size() > 1) + { + std::vector::iterator iter = mViews.begin(); + + if ((*iter) != lastView) + (*iter)->close(); + else (*(++iter))->close(); + } + + lastView->close(); +} diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 2517f8ccbe..92df13785f 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -27,17 +27,16 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; - View *mCloseMeOnSaveStateChange; - int mPreviousDocumentState; + std::vector::iterator mCloseMeOnSaveStateChange; + bool mUserWarned; // not implemented ViewManager (const ViewManager&); ViewManager& operator= (const ViewManager&); void updateIndices(); - bool showModifiedDocumentMessageBox (View* view); - bool showSaveInProgressMessageBox (View* view); - + bool showModifiedDocumentMessageBox (std::vector::iterator view); + bool showSaveInProgressMessageBox (std::vector::iterator view); public: @@ -59,11 +58,19 @@ namespace CSVDoc void loadDocumentRequest(); + void closeMessageBox(); + + public slots: + + void closeAllViews (View *lastView); + private slots: void documentStateChanged (int state, CSMDoc::Document *document); void progress (int current, int max, int type, int threads, CSMDoc::Document *document); + + void onCloseWarningHandler(int state, CSMDoc::Document* document); }; } From 40b6b4afc5f7fb69d8db5849905b6eed841b184d Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Fri, 8 Mar 2013 11:31:52 +0100 Subject: [PATCH 0636/1483] fix cmake typo that effects windows devs --- cmake/FindFFmpeg.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index 4147590d60..a3509597b2 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -99,7 +99,7 @@ endmacro() # Check for cached results. If there are skip the costly part. if (NOT FFMPEG_LIBRARIES) - set (FFMPEGSDK ENV${FFMPEG_HOME}) + set (FFMPEGSDK $ENV{FFMPEG_HOME}) if (FFMPEGSDK) set (FFMPEGSDK_INC "${FFMPEGSDK}/include") set (FFMPEGSDK_LIB "${FFMPEGSDK}/lib") From 207f78ab77ed1e250598e32b65819a9a19b4d1ad Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Fri, 8 Mar 2013 15:30:53 +0100 Subject: [PATCH 0637/1483] added two additional required boost libs to build on windows, one of which is already pulled by other boost lib in Ubuntu. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3950274790..7a7c803e79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,7 +183,7 @@ endif() # find boost without components so we can use Boost_VERSION find_package(Boost REQUIRED) -set(BOOST_COMPONENTS system filesystem program_options thread) +set(BOOST_COMPONENTS system filesystem program_options thread date_time chrono) if (Boost_VERSION LESS 104900) set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE") From d7c4a622cf196e84c337a9eed31929e82a0429d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 Mar 2013 23:46:25 +0100 Subject: [PATCH 0638/1483] Create a separate rigid body / shape with full details for raycasting, remove the occlusion query hack --- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwrender/occlusionquery.cpp | 120 +----------- apps/openmw/mwrender/occlusionquery.hpp | 35 ---- apps/openmw/mwworld/physicssystem.cpp | 18 +- apps/openmw/mwworld/worldimp.cpp | 123 +------------ apps/openmw/mwworld/worldimp.hpp | 5 +- components/nifbullet/bulletnifloader.cpp | 136 ++++++++------ components/nifbullet/bulletnifloader.hpp | 11 +- libs/openengine/bullet/BulletShapeLoader.cpp | 21 ++- libs/openengine/bullet/BulletShapeLoader.h | 10 +- libs/openengine/bullet/physic.cpp | 183 ++++++++++--------- libs/openengine/bullet/physic.hpp | 16 +- libs/openengine/bullet/trace.cpp | 2 +- 13 files changed, 238 insertions(+), 444 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 1b82d741c1..0fd24601a8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -32,7 +32,7 @@ namespace MWGui , mBalanceChangePause(0.0) { // items the NPC is wearing should not be for trade - mDisplayEquippedItems = true; + mDisplayEquippedItems = false; MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 81a3f43274..eaa155b066 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -13,9 +13,9 @@ using namespace MWRender; using namespace Ogre; OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : - mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0), - mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), - mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), + mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mActiveQuery(0), + mDoQuery(0), mSunVisibility(0), + mWasVisible(false), mBBNode(0), mActive(false) { mRendering = renderer; @@ -26,9 +26,8 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mSunTotalAreaQuery = renderSystem->createHardwareOcclusionQuery(); mSunVisibleAreaQuery = renderSystem->createHardwareOcclusionQuery(); - mSingleObjectQuery = renderSystem->createHardwareOcclusionQuery(); - mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0) && (mSingleObjectQuery != 0); + mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0); } catch (Ogre::Exception e) { @@ -56,7 +55,6 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod if (sunNode) mBBNode = mSunNode->getParentSceneNode()->createChildSceneNode(); - mObjectNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mBBQueryTotal = mRendering->getScene()->createBillboardSet(1); @@ -77,16 +75,6 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQueryVisible->setVisibilityFlags(RV_OcclusionQuery); mBBNodeReal->attachObject(mBBQueryVisible); - mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); - /// \todo ideally this should occupy exactly 1 pixel on the screen - mBBQuerySingleObject->setCastShadows(false); - mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003); - mBBQuerySingleObject->createBillboard(Vector3::ZERO); - mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); - mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery); - mBBQuerySingleObject->setVisibilityFlags(RV_OcclusionQuery); - mObjectNode->attachObject(mBBQuerySingleObject); - mRendering->getScene()->addRenderObjectListener(this); mRendering->getScene()->addRenderQueueListener(this); mDoQuery = true; @@ -98,9 +86,10 @@ OcclusionQuery::~OcclusionQuery() mRendering->getScene()->removeRenderQueueListener(this); RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); - if (mSunTotalAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); - if (mSunVisibleAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); - if (mSingleObjectQuery) renderSystem->destroyHardwareOcclusionQuery(mSingleObjectQuery); + if (mSunTotalAreaQuery) + renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); + if (mSunVisibleAreaQuery) + renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); } bool OcclusionQuery::supported() @@ -137,13 +126,6 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass mActiveQuery = mSunVisibleAreaQuery; } } - if (mDoQuery == true && rend == mBBQuerySingleObject) - { - mQuerySingleObjectStarted = true; - mQuerySingleObjectRequested = false; - mActiveQuery = mSingleObjectQuery; - mObjectWasVisible = true; - } if (mActiveQuery != NULL) mActiveQuery->beginOcclusionQuery(); @@ -173,13 +155,6 @@ void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocati mSunVisibleAreaQuery->beginOcclusionQuery(); mSunVisibleAreaQuery->endOcclusionQuery(); } - if (mObjectWasVisible == false && mDoQuery) - { - mSingleObjectQuery->beginOcclusionQuery(); - mSingleObjectQuery->endOcclusionQuery(); - mQuerySingleObjectStarted = true; - mQuerySingleObjectRequested = false; - } } } @@ -188,7 +163,6 @@ void OcclusionQuery::update(float duration) if (!mSupported) return; mWasVisible = false; - mObjectWasVisible = false; // Adjust the position of the sun billboards according to camera viewing distance // we need to do this to make sure that _everything_ can occlude the sun @@ -209,8 +183,7 @@ void OcclusionQuery::update(float duration) mDoQuery = false; if (!mSunTotalAreaQuery->isStillOutstanding() - && !mSunVisibleAreaQuery->isStillOutstanding() - && !mSingleObjectQuery->isStillOutstanding()) + && !mSunVisibleAreaQuery->isStillOutstanding()) { unsigned int totalPixels; unsigned int visiblePixels; @@ -229,88 +202,13 @@ void OcclusionQuery::update(float duration) if (mSunVisibility > 1) mSunVisibility = 1; } - unsigned int result; - - mSingleObjectQuery->pullOcclusionQuery(&result); - - mTestResult = (result != 0); - - mQuerySingleObjectStarted = false; - mQuerySingleObjectRequested = false; - mDoQuery = true; } } -void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNode* object) -{ - assert( !occlusionTestPending() - && "Occlusion test still pending"); - - mBBQuerySingleObject->setVisible(true); - - mObjectNode->setPosition(position); - // scale proportional to camera distance, in order to always give the billboard the same size in screen-space - mObjectNode->setScale( Vector3(1,1,1)*(position - mRendering->getCamera()->getRealPosition()).length() ); - - mQuerySingleObjectRequested = true; - - mDoQuery = true; -} - -bool OcclusionQuery::occlusionTestPending() -{ - return (mQuerySingleObjectRequested || mQuerySingleObjectStarted); -} - void OcclusionQuery::setSunNode(Ogre::SceneNode* node) { mSunNode = node; if (!mBBNode) mBBNode = node->getParentSceneNode()->createChildSceneNode(); } - -bool OcclusionQuery::getTestResult() -{ - assert( !occlusionTestPending() - && "Occlusion test still pending"); - - return mTestResult; -} - -bool OcclusionQuery::isPotentialOccluder(Ogre::SceneNode* node) -{ - bool result = false; - for (unsigned int i=0; i < node->numAttachedObjects(); ++i) - { - MovableObject* ob = node->getAttachedObject(i); - std::string type = ob->getMovableType(); - if (type == "Entity") - { - Entity* ent = static_cast(ob); - for (unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - // if any sub entity has a material with depth write off, - // consider the object as not an occluder - MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); - - Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) - { - Technique* tech = techIt.getNext(); - Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) - { - Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) - return false; - else - result = true; - } - } - } - } - } - return result; -} diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index c7a5757d3c..145d773553 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -40,31 +40,6 @@ namespace MWRender */ void update(float duration); - /** - * request occlusion test for a billboard at the given position, omitting an entity - * @param position of the billboard in ogre coordinates - * @param object to exclude from the occluders - */ - void occlusionTest(const Ogre::Vector3& position, Ogre::SceneNode* object); - - /** - * @return true if a request is still outstanding - */ - bool occlusionTestPending(); - - /** - * Checks if the objects held by this scenenode - * can be considered as potential occluders - * (which might not be the case when transparency is involved) - * @param Scene node - */ - bool isPotentialOccluder(Ogre::SceneNode* node); - - /** - * @return true if the object tested in the last request was occluded - */ - bool getTestResult(); - float getSunVisibility() const {return mSunVisibility;}; void setSunNode(Ogre::SceneNode* node); @@ -72,33 +47,23 @@ namespace MWRender private: Ogre::HardwareOcclusionQuery* mSunTotalAreaQuery; Ogre::HardwareOcclusionQuery* mSunVisibleAreaQuery; - Ogre::HardwareOcclusionQuery* mSingleObjectQuery; Ogre::HardwareOcclusionQuery* mActiveQuery; Ogre::BillboardSet* mBBQueryVisible; Ogre::BillboardSet* mBBQueryTotal; - Ogre::BillboardSet* mBBQuerySingleObject; Ogre::SceneNode* mSunNode; Ogre::SceneNode* mBBNode; Ogre::SceneNode* mBBNodeReal; float mSunVisibility; - Ogre::SceneNode* mObjectNode; - bool mWasVisible; - bool mObjectWasVisible; - - bool mTestResult; bool mActive; bool mSupported; bool mDoQuery; - bool mQuerySingleObjectRequested; - bool mQuerySingleObjectStarted; - OEngine::Render::OgreRenderer* mRendering; protected: diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 895517481b..7edd202935 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -370,7 +370,9 @@ namespace MWWorld Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); handleToMesh[node->getName()] = mesh; OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody(mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation()); - mEngine->addRigidBody(body); + OEngine::Physic::RigidBody* raycastingBody = mEngine->createAndAdjustRigidBody + (mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, true); + mEngine->addRigidBody(body, true, raycastingBody); } void PhysicsSystem::addActor (const Ptr& ptr) @@ -395,9 +397,14 @@ namespace MWWorld Ogre::SceneNode *node = ptr.getRefData().getBaseNode(); const std::string &handle = node->getName(); const Ogre::Vector3 &position = node->getPosition(); + if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle)) body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); - else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) + + if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle, true)) + body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); + + if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) physact->setPosition(position); } @@ -418,6 +425,13 @@ namespace MWWorld else mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); } + if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle, true)) + { + if(dynamic_cast(body->getCollisionShape()) == NULL) + body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); + else + mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); + } } void PhysicsSystem::scaleObject (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 33a9b52bf6..4b06d6a083 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1018,42 +1018,10 @@ namespace MWWorld mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } - // update faced handle (object the player is looking at) - // this uses a mixture of raycasts and occlusion queries. - else // if (mRendering->occlusionQuerySupported()) - { - MWRender::OcclusionQuery* query = mRendering->getOcclusionQuery(); - if (!query->occlusionTestPending()) - { - processFacedQueryResults (query); - beginFacedQueryProcess (query); - } - } + updateFacedHandle (); } - void World::processFacedQueryResults (MWRender::OcclusionQuery* query) - { - // get result of last query - if (mNumFacing == 0) - { - mFacedHandle = ""; - mFacedDistance = FLT_MAX; - } - else if (mNumFacing == 1) - { - bool result = query->getTestResult(); - mFacedHandle = result ? mFaced1Name : ""; - mFacedDistance = result ? mFaced1Distance : FLT_MAX; - } - else if (mNumFacing == 2) - { - bool result = query->getTestResult(); - mFacedHandle = result ? mFaced2Name : mFaced1Name; - mFacedDistance = result ? mFaced1Distance : mFaced1Distance; - } - } - - void World::beginFacedQueryProcess (MWRender::OcclusionQuery* query) + void World::updateFacedHandle () { // send new query // figure out which object we want to test against @@ -1084,95 +1052,16 @@ namespace MWWorld if (results.size() == 0) { - mNumFacing = 0; - } - else if (results.size() == 1) - { - beginSingleFacedQueryProcess (query, results); + mFacedHandle = ""; + mFacedDistance = FLT_MAX; } else { - beginDoubleFacedQueryProcess (query, results); + mFacedHandle = results.front().second; + mFacedDistance = results.front().first; } } - void World::beginSingleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results) - { - mFaced1 = getPtrViaHandle(results.front().second); - mFaced1Name = results.front().second; - mFaced1Distance = results.front().first; - mNumFacing = 1; - - btVector3 p; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - float x, y; - MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - p = mPhysics->getRayPoint(results.front().first, x, y); - } - else - p = mPhysics->getRayPoint(results.front().first); - Ogre::Vector3 pos(p.x(), p.y(), p.z()); - Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); - - //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; - //std::cout << "Type 1 " << mFaced1.getTypeName() << std::endl; - - query->occlusionTest(pos, node); - } - - void World::beginDoubleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results) - { - mFaced1Name = results.at (0).second; - mFaced2Name = results.at (1).second; - mFaced1Distance = results.at (0).first; - mFaced2Distance = results.at (1).first; - mFaced1 = getPtrViaHandle(results.at (0).second); - mFaced2 = getPtrViaHandle(results.at (1).second); - mNumFacing = 2; - - btVector3 p; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - float x, y; - MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - p = mPhysics->getRayPoint(results.at (1).first, x, y); - } - else - p = mPhysics->getRayPoint(results.at (1).first); - Ogre::Vector3 pos(p.x(), p.y(), p.z()); - Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); - Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); - - // no need to test if the first node is not occluder - if (!query->isPotentialOccluder(node1) && (mFaced1.getTypeName().find("Static") == std::string::npos)) - { - mFacedHandle = mFaced1Name; - mFacedDistance = mFaced1Distance; - //std::cout << "node1 Not an occluder" << std::endl; - return; - } - - // no need to test if the second object is static (thus cannot be activated) - if (mFaced2.getTypeName().find("Static") != std::string::npos) - { - mFacedHandle = mFaced1Name; - mFacedDistance = mFaced1Distance; - return; - } - - // work around door problems - if (mFaced1.getTypeName().find("Static") != std::string::npos - && mFaced2.getTypeName().find("Door") != std::string::npos) - { - mFacedHandle = mFaced2Name; - mFacedDistance = mFaced2Distance; - return; - } - - query->occlusionTest(pos, node2); - } - bool World::isCellExterior() const { Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index fe4ceff692..e06b89f600 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -97,10 +97,7 @@ namespace MWWorld void updateWindowManager (); void performUpdateSceneQueries (); - void processFacedQueryResults (MWRender::OcclusionQuery* query); - void beginFacedQueryProcess (MWRender::OcclusionQuery* query); - void beginSingleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results); - void beginDoubleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results); + void updateFacedHandle (); float getMaxActivationDistance (); float getNpcActivationDistance (); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 91fd6dbcfa..192eb9aaf7 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -22,9 +22,11 @@ http://www.gnu.org/licenses/ . */ #include "bulletnifloader.hpp" -#include + #include +#include + #include "../nif/niffile.hpp" #include "../nif/node.hpp" #include "../nif/data.hpp" @@ -46,6 +48,20 @@ typedef unsigned char ubyte; namespace NifBullet { +struct TriangleMeshShape : public btBvhTriangleMeshShape +{ + TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) + : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) + { + } + + virtual ~TriangleMeshShape() + { + delete getTriangleInfoMap(); + delete m_meshInterface; + } +}; + ManualBulletShapeLoader::~ManualBulletShapeLoader() { } @@ -62,10 +78,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) resourceName = cShape->getName(); cShape->mCollide = false; mBoundingBox = NULL; - cShape->boxTranslation = Ogre::Vector3(0,0,0); - cShape->boxRotation = Ogre::Quaternion::IDENTITY; + cShape->mBoxTranslation = Ogre::Vector3(0,0,0); + cShape->mBoxRotation = Ogre::Quaternion::IDENTITY; + mHasShape = false; - mTriMesh = new btTriangleMesh(); + btTriangleMesh* mesh1 = new btTriangleMesh(); // 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 @@ -94,35 +111,43 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool hasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(node,0,hasCollisionNode,false,false); - - //if collide = false, then it does a second pass which create a shape for raycasting. - if(cShape->mCollide == false) - handleNode(node,0,hasCollisionNode,false,true); - - //cShape->collide = hasCollisionNode&&cShape->collide; - - struct TriangleMeshShape : public btBvhTriangleMeshShape - { - TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) - : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) - { - } - - virtual ~TriangleMeshShape() - { - delete getTriangleInfoMap(); - delete m_meshInterface; - } - }; + handleNode(mesh1, node,0,hasCollisionNode,false,false); if(mBoundingBox != NULL) - cShape->Shape = mBoundingBox; - else { - currentShape = new TriangleMeshShape(mTriMesh,true); - cShape->Shape = currentShape; + cShape->mCollisionShape = mBoundingBox; + delete mesh1; } + else if (mHasShape && !cShape->mIgnore && cShape->mCollide) + { + cShape->mCollisionShape = new TriangleMeshShape(mesh1,true); + } + else + delete mesh1; + + //second pass which create a shape for raycasting. + resourceName = cShape->getName(); + cShape->mCollide = false; + mBoundingBox = NULL; + cShape->mBoxTranslation = Ogre::Vector3(0,0,0); + cShape->mBoxRotation = Ogre::Quaternion::IDENTITY; + mHasShape = false; + + btTriangleMesh* mesh2 = new btTriangleMesh(); + + handleNode(mesh2, node,0,hasCollisionNode,true,true); + + if(mBoundingBox != NULL) + { + cShape->mRaycastingShape = mBoundingBox; + delete mesh2; + } + else if (mHasShape && !cShape->mIgnore) + { + cShape->mRaycastingShape = new TriangleMeshShape(mesh2,true); + } + else + delete mesh2; } bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) @@ -147,22 +172,26 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) return false; } -void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, +void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *node, int flags, bool hasCollisionNode, bool isCollisionNode, - bool raycastingOnly) + bool raycasting) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. flags |= node->flags; - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); + if (!raycasting) + isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); + else + isCollisionNode = isCollisionNode && (node->recType != Nif::RC_RootCollisionNode); // Marker objects: no collision /// \todo don't do this in the editor - if (node->name.find("marker") != std::string::npos) + std::string nodename = node->name; + boost::algorithm::to_lower(nodename); + if (nodename.find("marker") != std::string::npos) { - flags |= 0x800; - cShape->mIgnore = true; + return; } // Check for extra data @@ -185,7 +214,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !raycastingOnly) + 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. @@ -193,20 +222,16 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } - if(!hasCollisionNode || isCollisionNode) + if(node->hasBounds) { - if(node->hasBounds) - { - cShape->boxTranslation = node->boundPos; - cShape->boxRotation = node->boundRot; - mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); - } - - if(node->recType == Nif::RC_NiTriShape) - { - cShape->mCollide = !(flags&0x800); - handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); - } + cShape->mBoxTranslation = node->boundPos; + cShape->mBoxRotation = node->boundRot; + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); + } + else if( (isCollisionNode || (!hasCollisionNode && !raycasting)) && node->recType == Nif::RC_NiTriShape) + { + cShape->mCollide = !(flags&0x800); + handleNiTriShape(mesh, static_cast(node), flags, node->getWorldTransform(), raycasting); } // For NiNodes, loop through children @@ -217,13 +242,13 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycastingOnly); + handleNode(mesh, list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycasting); } } } -void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, - bool raycastingOnly) +void ManualBulletShapeLoader::handleNiTriShape(btTriangleMesh* mesh, const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, + bool raycasting) { assert(shape != NULL); @@ -234,18 +259,19 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. - if (flags & 0x800 && !raycastingOnly) + if ((flags & 0x800) && !raycasting) { collide = false; bbcollide = false; return; } - if (!collide && !bbcollide && hidden && !raycastingOnly) + if (!collide && !bbcollide && hidden && !raycasting) // This mesh apparently isn't being used for anything, so don't // bother setting it up. return; + mHasShape = true; const Nif::NiTriShapeData *data = shape->data.getPtr(); const std::vector &vertices = data->vertices; @@ -255,7 +281,7 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; - mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); + mesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 0ff4b4ccd7..9cb5a3e86e 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -24,13 +24,12 @@ #ifndef OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP #define OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP -#include #include #include #include #include #include -#include "openengine/bullet/BulletShapeLoader.h" +#include // For warning messages #include @@ -83,7 +82,7 @@ private: /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycastingOnly); + void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycasting); /** *Helper function @@ -93,15 +92,15 @@ private: /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycastingOnly); + void handleNiTriShape(btTriangleMesh* mesh, const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycasting); std::string resourceName; std::string resourceGroup; OEngine::Physic::BulletShape* cShape;//current shape - btTriangleMesh *mTriMesh; btBoxShape *mBoundingBox; - btBvhTriangleMeshShape* currentShape;//the shape curently under construction + + bool mHasShape; }; } diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 071a5ee8a9..8744c4e4d6 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -17,7 +17,8 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) list all the options that need to be set before loading, of which we have none as such. Full details can be set through scripts. */ - Shape = NULL; + mCollisionShape = NULL; + mRaycastingShape = NULL; mCollide = true; mIgnore = false; createParamDictionary("BulletShape"); @@ -25,7 +26,8 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) BulletShape::~BulletShape() { - deleteShape(Shape); + deleteShape(mCollisionShape); + deleteShape(mRaycastingShape); } // farm out to BulletShapeLoader @@ -34,27 +36,28 @@ void BulletShape::loadImpl() mLoader->loadResource(this); } -void BulletShape::deleteShape(btCollisionShape* mShape) +void BulletShape::deleteShape(btCollisionShape* shape) { - if(mShape!=NULL) + if(shape!=NULL) { - if(mShape->isCompound()) + if(shape->isCompound()) { - btCompoundShape* ms = static_cast(Shape); + btCompoundShape* ms = static_cast(mCollisionShape); int a = ms->getNumChildShapes(); for(int i=0; i getChildShape(i)); } } - delete mShape; + delete shape; } - mShape = NULL; + shape = NULL; } void BulletShape::unloadImpl() { - deleteShape(Shape); + deleteShape(mCollisionShape); + deleteShape(mRaycastingShape); } //TODO:change this? diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index d9bd5879af..fa03b02766 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -22,7 +22,7 @@ protected: void unloadImpl(); size_t calculateSize() const; - void deleteShape(btCollisionShape* mShape); + void deleteShape(btCollisionShape* shape); public: @@ -32,9 +32,11 @@ public: virtual ~BulletShape(); - btCollisionShape* Shape; - Ogre::Vector3 boxTranslation; - Ogre::Quaternion boxRotation; + btCollisionShape* mCollisionShape; + btCollisionShape* mRaycastingShape; + + Ogre::Vector3 mBoxTranslation; + Ogre::Quaternion mBoxRotation; //this flag indicate if the shape is used for collision or if it's for raycasting only. bool mCollide; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e5d7c367ff..c4947af1e1 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -25,11 +25,10 @@ namespace Physic if(name == "player") collisionMode = false; mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); + mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation, true); Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); - mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map - //mBody->setCollisionFlags(COL_NOTHING); - //mBody->setMas + mEngine->addRigidBody(mBody, false, mRaycastingBody); //Add rigid body to dynamics world, but do not add to object map } PhysicActor::~PhysicActor() @@ -39,6 +38,11 @@ namespace Physic mEngine->dynamicsWorld->removeRigidBody(mBody); delete mBody; } + if(mRaycastingBody) + { + mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody); + delete mRaycastingBody; + } } void PhysicActor::enableCollisions(bool collision) @@ -52,13 +56,18 @@ namespace Physic void PhysicActor::setPosition(const Ogre::Vector3 &pos) { if(pos != getPosition()) + { mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); + mEngine->adjustRigidBody(mRaycastingBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); + } } void PhysicActor::setRotation(const Ogre::Quaternion &quat) { if(!quat.equals(getRotation(), Ogre::Radian(0))){ mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); + mEngine->adjustRigidBody(mRaycastingBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); + } } @@ -135,7 +144,6 @@ namespace Physic RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name) : btRigidBody(CI) , mName(name) - , mIgnore(false) { } @@ -226,8 +234,19 @@ namespace Physic delete hf_it->second.mBody; } - RigidBodyContainer::iterator rb_it = ObjectMap.begin(); - for (; rb_it != ObjectMap.end(); ++rb_it) + RigidBodyContainer::iterator rb_it = mCollisionObjectMap.begin(); + for (; rb_it != mCollisionObjectMap.end(); ++rb_it) + { + if (rb_it->second != NULL) + { + dynamicsWorld->removeRigidBody(rb_it->second); + + delete rb_it->second; + rb_it->second = NULL; + } + } + rb_it = mRaycastingObjectMap.begin(); + for (; rb_it != mRaycastingObjectMap.end(); ++rb_it) { if (rb_it->second != NULL) { @@ -243,8 +262,6 @@ namespace Physic { if (pa_it->second != NULL) { - - delete pa_it->second; pa_it->second = NULL; } @@ -296,7 +313,6 @@ namespace Physic btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,hfShape); RigidBody* body = new RigidBody(CI,name); - body->mCollide = true; body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); HeightField hf; @@ -347,12 +363,12 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); + adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); } RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation) + Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting) { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; @@ -361,72 +377,77 @@ namespace Physic mShapeLoader->load(outputstring,"General"); BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - shape->Shape->setLocalScaling( btVector3(scale,scale,scale)); + if (!shape->mCollisionShape && !raycasting) + return NULL; + if (!shape->mRaycastingShape && raycasting) + return NULL; + + if (!raycasting) + shape->mCollisionShape->setLocalScaling( btVector3(scale,scale,scale)); + else + shape->mRaycastingShape->setLocalScaling( btVector3(scale,scale,scale)); //create the motionState CMotionState* newMotionState = new CMotionState(this,name); //create the real body - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,shape->Shape); + btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo + (0,newMotionState, raycasting ? shape->mRaycastingShape : shape->mCollisionShape); RigidBody* body = new RigidBody(CI,name); - body->mCollide = shape->mCollide; - body->mIgnore = shape->mIgnore; if(scaledBoxTranslation != 0) - *scaledBoxTranslation = shape->boxTranslation * scale; + *scaledBoxTranslation = shape->mBoxTranslation * scale; if(boxRotation != 0) - *boxRotation = shape->boxRotation; + *boxRotation = shape->mBoxRotation; - adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); + adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); return body; } - void PhysicEngine::addRigidBody(RigidBody* body, bool addToMap) + void PhysicEngine::addRigidBody(RigidBody* body, bool addToMap, RigidBody* raycastingBody) { - if(body) - { - if (body->mIgnore) - return; - if(body->mCollide) - { - dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); - } - else - { - dynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_World); - } - body->setActivationState(DISABLE_DEACTIVATION); - if(addToMap){ - RigidBody* oldBody = ObjectMap[body->mName]; - if (oldBody != NULL) - { - dynamicsWorld->removeRigidBody(oldBody); - delete oldBody; - } + if(!body && !raycastingBody) + return; // nothing to do - ObjectMap[body->mName] = body; - } + const std::string& name = (body ? body->mName : raycastingBody->mName); + + if (body) + dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); + + if (raycastingBody) + dynamicsWorld->addRigidBody(raycastingBody,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_World); + + if(addToMap){ + removeRigidBody(name); + deleteRigidBody(name); + + if (body) + mCollisionObjectMap[name] = body; + if (raycastingBody) + mRaycastingObjectMap[name] = raycastingBody; } } void PhysicEngine::removeRigidBody(const std::string &name) { - RigidBodyContainer::iterator it = ObjectMap.find(name); - if (it != ObjectMap.end() ) + RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); + if (it != mCollisionObjectMap.end() ) + { + RigidBody* body = it->second; + if(body != NULL) + { + dynamicsWorld->removeRigidBody(body); + } + } + it = mRaycastingObjectMap.find(name); + if (it != mRaycastingObjectMap.end() ) { RigidBody* body = it->second; if(body != NULL) { - // broadphase->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher); - /*PhysicActorContainer::iterator it2 = PhysicActorMap.begin(); - for(;it2!=PhysicActorMap.end();it++) - { - it2->second->internalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher); - it2->second->externalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher); - }*/ dynamicsWorld->removeRigidBody(body); } } @@ -434,35 +455,42 @@ namespace Physic void PhysicEngine::deleteRigidBody(const std::string &name) { - RigidBodyContainer::iterator it = ObjectMap.find(name); - if (it != ObjectMap.end() ) + RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); + if (it != mCollisionObjectMap.end() ) { RigidBody* body = it->second; - //btScaledBvhTriangleMeshShape* scaled = dynamic_cast (body->getCollisionShape()); if(body != NULL) { delete body; } - /*if(scaled != NULL) + mCollisionObjectMap.erase(it); + } + it = mRaycastingObjectMap.find(name); + if (it != mRaycastingObjectMap.end() ) + { + RigidBody* body = it->second; + + if(body != NULL) { - delete scaled; - }*/ - ObjectMap.erase(it); + delete body; + } + mRaycastingObjectMap.erase(it); } } - RigidBody* PhysicEngine::getRigidBody(const std::string &name) + RigidBody* PhysicEngine::getRigidBody(const std::string &name, bool raycasting) { - RigidBodyContainer::iterator it = ObjectMap.find(name); - if (it != ObjectMap.end() ) + RigidBodyContainer* map = raycasting ? &mRaycastingObjectMap : &mCollisionObjectMap; + RigidBodyContainer::iterator it = map->find(name); + if (it != map->end() ) { - RigidBody* body = ObjectMap[name]; + RigidBody* body = (*map)[name]; return body; } else { - return 0; + return NULL; } } @@ -530,7 +558,7 @@ namespace Physic float d1 = 10000.; btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_Raycasting; + resultCallback1.m_collisionFilterMask = CollisionType_Raycasting; dynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit()) { @@ -539,35 +567,16 @@ namespace Physic d = d1; } - btCollisionWorld::ClosestRayResultCallback resultCallback2(from, to); - resultCallback2.m_collisionFilterMask = CollisionType_ActorInternal|CollisionType_ActorExternal; - dynamicsWorld->rayTest(from, to, resultCallback2); - float d2 = 10000.; - if (resultCallback2.hasHit()) - { - d2 = resultCallback1.m_closestHitFraction; - if(d2<=d1) - { - name = static_cast(*resultCallback2.m_collisionObject).mName; - d = d2; - } - } - return std::pair(name,d); } std::vector< std::pair > PhysicEngine::rayTest2(btVector3& from, btVector3& to) { MyRayResultCallback resultCallback1; - resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_Raycasting; + resultCallback1.m_collisionFilterMask = CollisionType_Raycasting; dynamicsWorld->rayTest(from, to, resultCallback1); std::vector< std::pair > results = resultCallback1.results; - MyRayResultCallback resultCallback2; - resultCallback2.m_collisionFilterMask = CollisionType_ActorInternal|CollisionType_ActorExternal; - dynamicsWorld->rayTest(from, to, resultCallback2); - std::vector< std::pair > actorResults = resultCallback2.results; - std::vector< std::pair > results2; for (std::vector< std::pair >::iterator it=results.begin(); @@ -576,12 +585,6 @@ namespace Physic results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); } - for (std::vector< std::pair >::iterator it=actorResults.begin(); - it != actorResults.end(); ++it) - { - results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); - } - std::sort(results2.begin(), results2.end(), MyRayResultCallback::cmp); return results2; @@ -600,6 +603,6 @@ namespace Physic btTransform trans; trans.setIdentity(); - shape->Shape->getAabb(trans, min, max); + shape->mCollisionShape->getAabb(trans, min, max); } }} diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 97fbbcea43..367db261fd 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -141,6 +141,7 @@ namespace Physic private: OEngine::Physic::RigidBody* mBody; + OEngine::Physic::RigidBody* mRaycastingBody; Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; @@ -163,10 +164,6 @@ namespace Physic RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name); virtual ~RigidBody(); std::string mName; - - //is this body used for raycasting only? - bool mCollide; - bool mIgnore; }; struct HeightField @@ -200,7 +197,7 @@ namespace Physic */ RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0); + Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool raycasting=false); /** * Adjusts a rigid body to the right position and rotation @@ -228,7 +225,7 @@ namespace Physic /** * Add a RigidBody to the simulation */ - void addRigidBody(RigidBody* body, bool addToMap = true); + void addRigidBody(RigidBody* body, bool addToMap = true, RigidBody* raycastingBody = NULL); /** * Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap. @@ -242,9 +239,8 @@ namespace Physic /** * Return a pointer to a given rigid body. - * TODO:check if exist */ - RigidBody* getRigidBody(const std::string &name); + RigidBody* getRigidBody(const std::string &name, bool raycasting=false); /** * Create and add a character to the scene, and add it to the ActorMap. @@ -322,7 +318,9 @@ namespace Physic HeightFieldContainer mHeightFieldMap; typedef std::map RigidBodyContainer; - RigidBodyContainer ObjectMap; + RigidBodyContainer mCollisionObjectMap; + + RigidBodyContainer mRaycastingObjectMap; typedef std::map PhysicActorContainer; PhysicActorContainer PhysicActorMap; diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index b6649199dc..cc443f2679 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -27,7 +27,7 @@ void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vec const btTransform to(btrot, btend); btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); - newTraceCallback.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_Raycasting; + newTraceCallback.m_collisionFilterMask = OEngine::Physic::CollisionType_World; enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); From c020665cf2dd556b307da0b57b625db4f305ffd0 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 9 Mar 2013 01:00:03 +0100 Subject: [PATCH 0639/1483] Fix appending int to string in an exception message --- apps/openmw/mwmechanics/alchemy.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 8ab81bfdf0..7182003720 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -144,7 +144,11 @@ void MWMechanics::Alchemy::updateEffects() MWBase::Environment::get().getWorld()->getStore().get().find (iter->mId); if (magicEffect->mData.mBaseCost<=0) - throw std::runtime_error ("invalid base cost for magic effect " + iter->mId); + { + std::ostringstream os; + os << "invalid base cost for magic effect " << iter->mId; + throw std::runtime_error (os.str()); + } float fPotionT1MagMul = MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionT1MagMult")->getFloat(); From b457c7de5e4341e150345468f356122bd8198fac Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sat, 9 Mar 2013 02:43:29 -0500 Subject: [PATCH 0640/1483] added linux opencs.desktop file --- CMakeLists.txt | 2 ++ opencs.desktop | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 opencs.desktop diff --git a/CMakeLists.txt b/CMakeLists.txt index 3950274790..dbe4c406bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,6 +300,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop + "${OpenMW_BINARY_DIR}/opencs.desktop") endif() # Compiler settings diff --git a/opencs.desktop b/opencs.desktop new file mode 100644 index 0000000000..f6aad5b097 --- /dev/null +++ b/opencs.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=OpenMW Content Editor +GenericName=Content Editor +Comment=A replacement for the Morrowind Construction Set. +TryExec=opencs +Exec=opencs +Icon=opencs +Categories=Game;RolePlaying; From 14964e9fcd4c14dad3b710a54a01e7bfdfc1674c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 Mar 2013 10:28:10 +0100 Subject: [PATCH 0641/1483] Only build a box shape for collision nodes; use StringUtils --- components/nifbullet/bulletnifloader.cpp | 26 ++++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 192eb9aaf7..af1243346a 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -25,7 +25,8 @@ http://www.gnu.org/licenses/ . #include -#include + +#include #include "../nif/niffile.hpp" #include "../nif/node.hpp" @@ -188,7 +189,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * // Marker objects: no collision /// \todo don't do this in the editor std::string nodename = node->name; - boost::algorithm::to_lower(nodename); + Misc::StringUtils::toLower(nodename); if (nodename.find("marker") != std::string::npos) { return; @@ -222,16 +223,19 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * } } - if(node->hasBounds) + if (isCollisionNode || (!hasCollisionNode && !raycasting)) { - cShape->mBoxTranslation = node->boundPos; - cShape->mBoxRotation = node->boundRot; - mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); - } - else if( (isCollisionNode || (!hasCollisionNode && !raycasting)) && node->recType == Nif::RC_NiTriShape) - { - cShape->mCollide = !(flags&0x800); - handleNiTriShape(mesh, static_cast(node), flags, node->getWorldTransform(), raycasting); + if(node->hasBounds) + { + cShape->mBoxTranslation = node->boundPos; + cShape->mBoxRotation = node->boundRot; + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); + } + else if(node->recType == Nif::RC_NiTriShape) + { + cShape->mCollide = !(flags&0x800); + handleNiTriShape(mesh, static_cast(node), flags, node->getWorldTransform(), raycasting); + } } // For NiNodes, loop through children From c8b31b4745df0558fcb603b8f4185ecdf20e6790 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 Mar 2013 13:26:00 +0100 Subject: [PATCH 0642/1483] Remove an outdated message --- apps/openmw/engine.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 62e106f3fb..f76590ae85 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -442,8 +442,6 @@ void OMW::Engine::go() 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(); From 5c94c654d48edc624b23e16aacbe8f46a0d6aff0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 Mar 2013 13:27:24 +0100 Subject: [PATCH 0643/1483] Fix wrong rotation of objects dropped on the ground --- apps/openmw/mwworld/worldimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b06d6a083..35ea8bbef7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1188,6 +1188,9 @@ namespace MWWorld pos.pos[0] = result.second[0]; pos.pos[1] = result.second[1]; pos.pos[2] = result.second[2]; + // We want only the Z part of the player's rotation + pos.rot[0] = 0; + pos.rot[1] = 0; Ptr dropped = copyObjectToCell(object, *cell, pos); PCDropped(dropped); @@ -1242,6 +1245,9 @@ namespace MWWorld ESM::Position pos = actor.getRefData().getPosition(); + // We want only the Z part of the actor's rotation + pos.rot[0] = 0; + pos.rot[1] = 0; Ogre::Vector3 orig = Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]); From b19571df895f91d5e1d8714f107c0eacbb2495d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 Mar 2013 14:59:50 +0100 Subject: [PATCH 0644/1483] If character creation dialogs are enabled in the wrong order, force creation stage to advance --- apps/openmw/mwgui/charactercreation.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 1719c57687..fbed0a874b 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -206,7 +206,9 @@ void CharacterCreation::spawnDialog(const char id) mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); - mRaceDialog->setVisible(true);; + mRaceDialog->setVisible(true); + if (mCreationStage < CSE_NameChosen) + mCreationStage = CSE_NameChosen; break; case GM_Class: @@ -215,6 +217,8 @@ void CharacterCreation::spawnDialog(const char id) mClassChoiceDialog = new ClassChoiceDialog(*mWM); mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); mClassChoiceDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; break; case GM_ClassPick: @@ -226,6 +230,8 @@ void CharacterCreation::spawnDialog(const char id) mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); mPickClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; break; case GM_Birth: @@ -237,6 +243,8 @@ void CharacterCreation::spawnDialog(const char id) mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); mBirthSignDialog->setVisible(true); + if (mCreationStage < CSE_ClassChosen) + mCreationStage = CSE_ClassChosen; break; case GM_ClassCreate: @@ -247,6 +255,8 @@ void CharacterCreation::spawnDialog(const char id) mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); mCreateClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; break; case GM_ClassGenerate: mGenerateClassStep = 0; @@ -255,6 +265,8 @@ void CharacterCreation::spawnDialog(const char id) mGenerateClassSpecializations[1] = 0; mGenerateClassSpecializations[2] = 0; showClassQuestionDialog(); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; break; case GM_Review: mWM->removeDialog(mReviewDialog); @@ -292,6 +304,8 @@ void CharacterCreation::spawnDialog(const char id) mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); mReviewDialog->setVisible(true); + if (mCreationStage < CSE_BirthSignChosen) + mCreationStage = CSE_BirthSignChosen; break; } } From b255472cc638eb1aec9b968d009dae28b93da44d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 9 Mar 2013 15:39:49 +0100 Subject: [PATCH 0645/1483] fixed a spelling mistake --- components/interpreter/controlopcodes.hpp | 46 +++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/components/interpreter/controlopcodes.hpp b/components/interpreter/controlopcodes.hpp index 534ccc4dd4..caa7559890 100644 --- a/components/interpreter/controlopcodes.hpp +++ b/components/interpreter/controlopcodes.hpp @@ -11,66 +11,66 @@ namespace Interpreter class OpReturn : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { runtime.setPC (-1); - } + } }; - + class OpSkipZero : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; runtime.pop(); - + if (data==0) runtime.setPC (runtime.getPC()+1); - } - }; - + } + }; + class OpSkipNonZero : public Opcode0 { public: - + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; runtime.pop(); - + if (data!=0) runtime.setPC (runtime.getPC()+1); - } - }; - + } + }; + class OpJumpForward : public Opcode1 { public: - + virtual void execute (Runtime& runtime, unsigned int arg0) { if (arg0==0) - throw std::logic_error ("inifite loop"); - + throw std::logic_error ("infinite loop"); + runtime.setPC (runtime.getPC()+arg0-1); - } - }; + } + }; class OpJumpBackward : public Opcode1 { public: - + virtual void execute (Runtime& runtime, unsigned int arg0) { if (arg0==0) - throw std::logic_error ("inifite loop"); - + throw std::logic_error ("infinite loop"); + runtime.setPC (runtime.getPC()-arg0-1); - } - }; + } + }; } #endif From 0ae48c1f83a7e8179ea9b1e6c923c43084080f89 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Sat, 9 Mar 2013 20:40:59 +0100 Subject: [PATCH 0646/1483] fix for Bug #509 --- apps/openmw/mwgui/list.cpp | 24 ++++++++++++++++++++++-- apps/openmw/mwgui/list.hpp | 20 ++++++++++++++------ apps/openmw/mwgui/windowmanagerimp.cpp | 1 + 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index d60e9b6877..8343c302a5 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -1,9 +1,9 @@ #include "list.hpp" -#include #include #include #include +#include using namespace MWGui; using namespace MWGui::Widgets; @@ -23,7 +23,7 @@ void MWList::initialiseOverride() if (mClient == 0) mClient = this; - mScrollView = mClient->createWidgetReal( + mScrollView = mClient->createWidgetReal( "MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); } @@ -48,6 +48,7 @@ void MWList::redraw(bool scrollbarShown) const int _scrollBarWidth = 24; // fetch this from skin? const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; const int spacing = 3; + size_t scrollbarPosition = mScrollView->getScrollPosition(); while (mScrollView->getChildCount()) { @@ -88,6 +89,11 @@ void MWList::redraw(bool scrollbarShown) if (!scrollbarShown && mItemHeight > mClient->getSize().height) redraw(true); + + size_t scrollbarRange = mScrollView->getScrollRange(); + if(scrollbarPosition > scrollbarRange) + scrollbarPosition = scrollbarRange; + mScrollView->setScrollPosition(scrollbarPosition); } bool MWList::hasItem(const std::string& name) @@ -138,3 +144,17 @@ MyGUI::Widget* MWList::getItemWidget(const std::string& name) { return mScrollView->findWidget (getName() + "_item_" + name); } + +size_t MWScrollView::getScrollPosition() +{ + return getVScroll()->getScrollPosition(); +} + +void MWScrollView::setScrollPosition(size_t position) +{ + getVScroll()->setScrollPosition(position); +} +size_t MWScrollView::getScrollRange() +{ + return getVScroll()->getScrollRange(); +} diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index 38797e7798..40e997459d 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -2,16 +2,24 @@ #define MWGUI_LIST_HPP #include - -namespace MyGUI -{ - class ScrollView; -} +#include namespace MWGui { namespace Widgets { + /** + * \brief a custom ScrollView which has access to scrollbar properties + */ + class MWScrollView : public MyGUI::ScrollView + { + MYGUI_RTTI_DERIVED(MWScrollView) + public: + size_t getScrollPosition(); + void setScrollPosition(size_t); + size_t getScrollRange(); + }; + /** * \brief a very simple list widget that supports word-wrapping entries * \note if the width or height of the list changes, you must call adjustSize() method @@ -63,7 +71,7 @@ namespace MWGui void onItemSelected(MyGUI::Widget* _sender); private: - MyGUI::ScrollView* mScrollView; + MWGui::Widgets::MWScrollView* mScrollView; MyGUI::Widget* mClient; std::vector mItems; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d866ec7557..0e4c3a6082 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -132,6 +132,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); From 391bad2ccb13e25c2c0ca0f485edcfb715f0189b Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sat, 9 Mar 2013 14:43:44 -0500 Subject: [PATCH 0647/1483] put .desktop file in the right directory --- opencs.desktop => files/opencs.desktop | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename opencs.desktop => files/opencs.desktop (100%) diff --git a/opencs.desktop b/files/opencs.desktop similarity index 100% rename from opencs.desktop rename to files/opencs.desktop From 289bbc64f749e54e0a02a6c5ca43e65dee04b360 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 9 Mar 2013 21:08:08 +0100 Subject: [PATCH 0648/1483] Load fallback archives listed in openmw.cfg at startup --- apps/openmw/engine.cpp | 23 +++++++++++++++++------ apps/openmw/engine.hpp | 6 +++++- apps/openmw/main.cpp | 10 ++++++++++ components/files/collections.cpp | 26 ++++++++++++++++++++++++++ components/files/collections.hpp | 10 ++++++++++ 5 files changed, 68 insertions(+), 7 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f76590ae85..ce84b8dfe1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -149,16 +149,22 @@ OMW::Engine::~Engine() delete mOgre; } -// Load all BSA files in data directory. +// Load BSA files void OMW::Engine::loadBSA() { - const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa"); - - for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter) + for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) { - std::cout << "Adding " << iter->second.string() << std::endl; - Bsa::addBSA(iter->second.string()); + if (mFileCollections.doesExist(*archive)) + { + const std::string archivePath = mFileCollections.getPath(*archive).string(); + std::cout << "Adding BSA archive " << archivePath << std::endl; + Bsa::addBSA(archivePath); + } + else + { + std::cout << "Archive " << *archive << " not found" << std::endl; + } } const Files::PathContainer& dataDirs = mFileCollections.getPaths(); @@ -199,6 +205,11 @@ void OMW::Engine::setDataDirs (const Files::PathContainer& dataDirs) mFileCollections = Files::Collections (dataDirs, !mFSStrict); } +// Add BSA archive +void OMW::Engine::addArchive (const std::string& archive) { + mArchives.push_back(archive); +} + // Set resource dir void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir) { diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index a4acee5232..f80b67a358 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -64,6 +64,7 @@ namespace OMW ToUTF8::FromType mEncoding; ToUTF8::Utf8Encoder* mEncoder; Files::PathContainer mDataDirs; + std::vector mArchives; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; std::string mCellName; @@ -99,7 +100,7 @@ namespace OMW /// add a .zip resource void addZipResource (const boost::filesystem::path& path); - /// Load all BSA files in data directory. + /// Load BSA files void loadBSA(); void executeLocalScripts(); @@ -126,6 +127,9 @@ namespace OMW /// Set data dirs void setDataDirs(const Files::PathContainer& dataDirs); + /// Add BSA archive + void addArchive(const std::string& archive); + /// Set resource dir void setResourceDir(const boost::filesystem::path& parResDir); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 86978c9b11..1fa461c2fb 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -100,6 +100,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("data-local", bpo::value()->default_value(""), "set local data directory (highest priority)") + ("fallback-archive", bpo::value()->default_value(StringsVector(), "fallback-archive") + ->multitoken(), "set fallback BSA archives (later archives have higher priority)") + ("resources", bpo::value()->default_value("resources"), "set resources directory") @@ -201,6 +204,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setDataDirs(dataDirs); + // fallback archives + StringsVector archives = variables["fallback-archive"].as(); + for (StringsVector::const_iterator it = archives.begin(); it != archives.end(); it++) + { + engine.addArchive(*it); + } + engine.setResourceDir(variables["resources"].as()); // master and plugin diff --git a/components/files/collections.cpp b/components/files/collections.cpp index 50340dca4d..c6195d88cf 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -31,6 +31,32 @@ namespace Files return iter->second; } + boost::filesystem::path Collections::getPath(const std::string& file) const + { + for (Files::PathContainer::const_iterator iter = mDirectories.begin(); + iter != mDirectories.end(); ++iter) + { + const boost::filesystem::path path = *iter / file; + if (boost::filesystem::exists(path)) + return path.string(); + } + + throw std::runtime_error ("file " + file + " not found"); + } + + bool Collections::doesExist(const std::string& file) const + { + for (Files::PathContainer::const_iterator iter = mDirectories.begin(); + iter != mDirectories.end(); ++iter) + { + const boost::filesystem::path path = *iter / file; + if (boost::filesystem::exists(path)) + return true; + } + + return false; + } + const Files::PathContainer& Collections::getPaths() const { return mDirectories; diff --git a/components/files/collections.hpp b/components/files/collections.hpp index ed4aafa133..def61cf8ef 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -19,6 +19,16 @@ namespace Files /// leading dot and must be all lower-case. const MultiDirCollection& getCollection(const std::string& extension) const; + boost::filesystem::path getPath(const std::string& file) const; + ///< Return full path (including filename) of \a file. + /// + /// If the file does not exist in any of the collection's + /// directories, an exception is thrown. \a file must include the + /// extension. + + bool doesExist(const std::string& file) const; + ///< \return Does a file with the given name exist? + const Files::PathContainer& getPaths() const; private: From a51b73b6091c3dadd6ab791161ddb09bc87410c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 Mar 2013 21:50:01 +0100 Subject: [PATCH 0649/1483] Fix topics that have the same name as a service opening that service when clicked --- apps/openmw/mwgui/dialogue.cpp | 88 +++++++++++++++++++--------------- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/list.cpp | 7 ++- apps/openmw/mwgui/list.hpp | 4 +- 4 files changed, 57 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 859e3008cc..cdcbfc4d18 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -223,50 +223,60 @@ void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } -void DialogueWindow::onSelectTopic(std::string topic) +void DialogueWindow::onSelectTopic(const std::string& topic, int id) { if (!mEnabled) return; - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); + int separatorPos = mTopicsList->getItemCount(); + for (unsigned int i=0; igetItemCount(); ++i) + { + if (mTopicsList->getItemNameAt(i) == "") + separatorPos = i; + } - if (topic == gmst.find("sBarter")->getString()) - { - /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? - mWindowManager.pushGuiMode(GM_Barter); - mWindowManager.getTradeWindow()->startTrade(mPtr); - } - if (topic == gmst.find("sPersuasion")->getString()) - { - mPersuasionDialog.setVisible(true); - } - else if (topic == gmst.find("sSpells")->getString()) - { - mWindowManager.pushGuiMode(GM_SpellBuying); - mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); - } - else if (topic == gmst.find("sTravel")->getString()) - { - mWindowManager.pushGuiMode(GM_Travel); - mWindowManager.getTravelWindow()->startTravel(mPtr); - } - else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - mWindowManager.pushGuiMode(GM_SpellCreation); - mWindowManager.startSpellMaking (mPtr); - } - else if (topic == gmst.find("sEnchanting")->getString()) - { - mWindowManager.pushGuiMode(GM_Enchanting); - mWindowManager.startEnchanting (mPtr); - } - else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - mWindowManager.pushGuiMode(GM_Training); - mWindowManager.startTraining (mPtr); - } - else + if (id > separatorPos) MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); + else + { + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (topic == gmst.find("sBarter")->getString()) + { + /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? + mWindowManager.pushGuiMode(GM_Barter); + mWindowManager.getTradeWindow()->startTrade(mPtr); + } + if (topic == gmst.find("sPersuasion")->getString()) + { + mPersuasionDialog.setVisible(true); + } + else if (topic == gmst.find("sSpells")->getString()) + { + mWindowManager.pushGuiMode(GM_SpellBuying); + mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); + } + else if (topic == gmst.find("sTravel")->getString()) + { + mWindowManager.pushGuiMode(GM_Travel); + mWindowManager.getTravelWindow()->startTravel(mPtr); + } + else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_SpellCreation); + mWindowManager.startSpellMaking (mPtr); + } + else if (topic == gmst.find("sEnchanting")->getString()) + { + mWindowManager.pushGuiMode(GM_Enchanting); + mWindowManager.startEnchanting (mPtr); + } + else if (topic == gmst.find("sServiceTrainingTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_Training); + mWindowManager.startTraining (mPtr); + } + } } void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index e39cecc3cf..a8e0a6d174 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -85,7 +85,7 @@ namespace MWGui }; protected: - void onSelectTopic(std::string topic); + void onSelectTopic(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); void onHistoryClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index 8343c302a5..c7b7207305 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -56,6 +56,7 @@ void MWList::redraw(bool scrollbarShown) } mItemHeight = 0; + int i=0; for (std::vector::const_iterator it=mItems.begin(); it!=mItems.end(); ++it) { @@ -72,6 +73,7 @@ void MWList::redraw(bool scrollbarShown) int height = button->getTextSize().height; button->setSize(MyGUI::IntSize(button->getSize().width, height)); + button->setUserData(i); mItemHeight += height + spacing; } @@ -84,6 +86,7 @@ void MWList::redraw(bool scrollbarShown) mItemHeight += 18 + spacing; } + ++i; } mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); @@ -135,8 +138,8 @@ void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) void MWList::onItemSelected(MyGUI::Widget* _sender) { std::string name = static_cast(_sender)->getCaption(); - - eventItemSelected(name); + int id = *_sender->getUserData(); + eventItemSelected(name, id); eventWidgetSelected(_sender); } diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index 40e997459d..09e42e865e 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -30,14 +30,14 @@ namespace MWGui public: MWList(); - typedef MyGUI::delegates::CMultiDelegate1 EventHandle_String; + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_StringInt; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Widget; /** * Event: Item selected with the mouse. * signature: void method(std::string itemName) */ - EventHandle_String eventItemSelected; + EventHandle_StringInt eventItemSelected; /** * Event: Item selected with the mouse. From aebd9a37001d1e84edd6ea073af8ba54d77dacb4 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 10 Mar 2013 00:24:14 +0100 Subject: [PATCH 0650/1483] Weather to pull --- apps/openmw/mwworld/weather.cpp | 330 +++++++++---------------------- apps/openmw/mwworld/weather.hpp | 124 ++---------- apps/openmw/mwworld/worldimp.cpp | 2 +- 3 files changed, 116 insertions(+), 340 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 514276f9bc..523f80985b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -19,262 +19,124 @@ using namespace MWWorld; using namespace MWSound; #define lerp(x, y) (x * (1-factor) + y * factor) +std::string WeatherManager::getFallback (const std::string& key) +{ + std::map::const_iterator it; + if((it = mFallback.find(key)) == mFallback.end()) + { + return ""; + } + return it->second; +} +std::string WeatherManager::getFallbackS(std::string fall) +{ + return WeatherManager::getFallback(fall); +} -const std::string WeatherGlobals::mThunderSoundID0 = "Thunder0"; -const std::string WeatherGlobals::mThunderSoundID1 = "Thunder1"; -const std::string WeatherGlobals::mThunderSoundID2 = "Thunder2"; -const std::string WeatherGlobals::mThunderSoundID3 = "Thunder3"; -const float WeatherGlobals::mSunriseTime = 8; -const float WeatherGlobals::mSunsetTime = 18; -const float WeatherGlobals::mSunriseDuration = 2; -const float WeatherGlobals::mSunsetDuration = 2; -const float WeatherGlobals::mWeatherUpdateTime = 20.f; +float WeatherManager::getFallbackF(std::string fall) +{ + return atof(getFallbackS(fall).c_str()); +} +ColourValue WeatherManager::getFallbackClr(std::string fall) +{ + std::string sum; + std::string ret[3]; + sum=getFallback(fall); + int j=0; + for(int i=0;i& fallbackMap) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0), mMonth(0), mDay(0), - mTimePassed(0) + mTimePassed(0), mFallback(fallbackMap) { mRendering = rendering; - - #define clr(r,g,b) ColourValue(r/255.f, g/255.f, b/255.f) - - /// \todo read these from Morrowind.ini - Weather clear; - clear.mCloudTexture = "tx_sky_clear.dds"; - clear.mCloudsMaximumPercent = 1.0; - clear.mTransitionDelta = 0.015; - clear.mSkySunriseColor = clr(118, 141, 164); - clear.mSkyDayColor = clr(95, 135, 203); - clear.mSkySunsetColor = clr(56, 89, 129); - clear.mSkyNightColor = clr(9, 10, 11); - clear.mFogSunriseColor = clr(255, 189, 157); - clear.mFogDayColor = clr(206, 227, 255); - clear.mFogSunsetColor = clr(255, 189, 157); - clear.mFogNightColor = clr(9, 10, 11); - clear.mAmbientSunriseColor = clr(47, 66, 96); - clear.mAmbientDayColor = clr(137, 140, 160); - clear.mAmbientSunsetColor = clr(68, 75, 96); - clear.mAmbientNightColor = clr(32, 35, 42); - clear.mSunSunriseColor = clr(242, 159, 99); - clear.mSunDayColor = clr(255, 252, 238); - clear.mSunSunsetColor = clr(255, 115, 79); - clear.mSunNightColor = clr(59, 97, 176); - clear.mSunDiscSunsetColor = clr(255, 189, 157); - clear.mLandFogDayDepth = 0.69; - clear.mLandFogNightDepth = 0.69; - clear.mWindSpeed = 0.1; - clear.mCloudSpeed = 1.25; - clear.mGlareView = 1.0; - mWeatherSettings["clear"] = clear; + //Globals + mThunderSoundID0 = getFallbackS("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = getFallbackS("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = getFallbackS("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = getFallbackS("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = getFallbackF("Weather_Sunrise_Time"); + mSunsetTime = getFallbackF("Weather_Sunset_Time"); + mSunriseDuration = getFallbackF("Weather_Sunrise_Duration"); + mSunsetDuration = getFallbackF("Weather_Sunset_Duration"); + mWeatherUpdateTime = getFallbackF("Weather_Hours_Between_Weather_Changes"); + mThunderFrequency = getFallbackF("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = getFallbackF("Weather_Thunderstorm_Thunder_Threshold"); + mThunderSoundDelay = 0.25; + //Weather + Weather clear; + clear.mCloudTexture = "tx_sky_clear.dds"; + setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mCloudTexture = "tx_sky_cloudy.dds"; - cloudy.mCloudsMaximumPercent = 1.0; - cloudy.mTransitionDelta = 0.015; - cloudy.mSkySunriseColor = clr(126, 158, 173); - cloudy.mSkyDayColor = clr(117, 160, 215); - cloudy.mSkySunsetColor = clr(111, 114, 159); - cloudy.mSkyNightColor = clr(9, 10, 11); - cloudy.mFogSunriseColor = clr(255, 207, 149); - cloudy.mFogDayColor = clr(245, 235, 224); - cloudy.mFogSunsetColor = clr(255, 155, 106); - cloudy.mFogNightColor = clr(9, 10, 11); - cloudy.mAmbientSunriseColor = clr(66, 74, 87); - cloudy.mAmbientDayColor = clr(137, 145, 160); - cloudy.mAmbientSunsetColor = clr(71, 80, 92); - cloudy.mAmbientNightColor = clr(32, 39, 54); - cloudy.mSunSunriseColor = clr(241, 177, 99); - cloudy.mSunDayColor = clr(255, 236, 221); - cloudy.mSunSunsetColor = clr(255, 89, 00); - cloudy.mSunNightColor = clr(77, 91, 124); - cloudy.mSunDiscSunsetColor = clr(255, 202, 179); - cloudy.mLandFogDayDepth = 0.72; - cloudy.mLandFogNightDepth = 0.72; - cloudy.mWindSpeed = 0.2; - cloudy.mCloudSpeed = 2; - cloudy.mGlareView = 1.0; - mWeatherSettings["cloudy"] = cloudy; + cloudy.mCloudTexture = "tx_sky_cloudy.dds"; + setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mCloudTexture = "tx_sky_foggy.dds"; - foggy.mCloudsMaximumPercent = 1.0; - foggy.mTransitionDelta = 0.015; - foggy.mSkySunriseColor = clr(197, 190, 180); - foggy.mSkyDayColor = clr(184, 211, 228); - foggy.mSkySunsetColor = clr(142, 159, 176); - foggy.mSkyNightColor = clr(18, 23, 28); - foggy.mFogSunriseColor = clr(173, 164, 148); - foggy.mFogDayColor = clr(150, 187, 209); - foggy.mFogSunsetColor = clr(113, 135, 157); - foggy.mFogNightColor = clr(19, 24, 29); - foggy.mAmbientSunriseColor = clr(48, 43, 37); - foggy.mAmbientDayColor = clr(92, 109, 120); - foggy.mAmbientSunsetColor = clr(28, 33, 39); - foggy.mAmbientNightColor = clr(28, 33, 39); - foggy.mSunSunriseColor = clr(177, 162, 137); - foggy.mSunDayColor = clr(111, 131, 151); - foggy.mSunSunsetColor = clr(125, 157, 189); - foggy.mSunNightColor = clr(81, 100, 119); - foggy.mSunDiscSunsetColor = clr(223, 223, 223); - foggy.mLandFogDayDepth = 1.0; - foggy.mLandFogNightDepth = 1.9; - foggy.mWindSpeed = 0; - foggy.mCloudSpeed = 1.25; - foggy.mGlareView = 0.25; - mWeatherSettings["foggy"] = foggy; + foggy.mCloudTexture = "tx_sky_foggy.dds"; + setFallbackWeather(foggy,"foggy"); Weather thunderstorm; thunderstorm.mCloudTexture = "tx_sky_thunder.dds"; - thunderstorm.mCloudsMaximumPercent = 0.66; - thunderstorm.mTransitionDelta = 0.03; - thunderstorm.mSkySunriseColor = clr(35, 36, 39); - thunderstorm.mSkyDayColor = clr(97, 104, 115); - thunderstorm.mSkySunsetColor = clr(35, 36, 39); - thunderstorm.mSkyNightColor = clr(19, 20, 22); - thunderstorm.mFogSunriseColor = clr(70, 74, 85); - thunderstorm.mFogDayColor = clr(97, 104, 115); - thunderstorm.mFogSunsetColor = clr(70, 74, 85); - thunderstorm.mFogNightColor = clr(19, 20, 22); - thunderstorm.mAmbientSunriseColor = clr(54, 54, 54); - thunderstorm.mAmbientDayColor = clr(90, 90, 90); - thunderstorm.mAmbientSunsetColor = clr(54, 54, 54); - thunderstorm.mAmbientNightColor = clr(49, 51, 54); - thunderstorm.mSunSunriseColor = clr(91, 99, 122); - thunderstorm.mSunDayColor = clr(138, 144, 155); - thunderstorm.mSunSunsetColor = clr(96, 101, 117); - thunderstorm.mSunNightColor = clr(55, 76, 110); - thunderstorm.mSunDiscSunsetColor = clr(128, 128, 128); - thunderstorm.mLandFogDayDepth = 1; - thunderstorm.mLandFogNightDepth = 1.15; - thunderstorm.mWindSpeed = 0.5; - thunderstorm.mCloudSpeed = 3; - thunderstorm.mGlareView = 0; thunderstorm.mRainLoopSoundID = "rain heavy"; - mWeatherSettings["thunderstorm"] = thunderstorm; + setFallbackWeather(thunderstorm,"thunderstorm"); Weather rain; rain.mCloudTexture = "tx_sky_rainy.dds"; - rain.mCloudsMaximumPercent = 0.66; - rain.mTransitionDelta = 0.015; - rain.mSkySunriseColor = clr(71, 74, 75); - rain.mSkyDayColor = clr(116, 120, 122); - rain.mSkySunsetColor = clr(73, 73, 73); - rain.mSkyNightColor = clr(24, 25, 26); - rain.mFogSunriseColor = clr(71, 74, 75); - rain.mFogDayColor = clr(116, 120, 122); - rain.mFogSunsetColor = clr(73, 73, 73); - rain.mFogNightColor = clr(24, 25, 26); - rain.mAmbientSunriseColor = clr(97, 90, 88); - rain.mAmbientDayColor = clr(105, 110, 113); - rain.mAmbientSunsetColor = clr(88, 97, 97); - rain.mAmbientNightColor = clr(50, 55, 67); - rain.mSunSunriseColor = clr(131, 122, 120); - rain.mSunDayColor = clr(149, 157, 170); - rain.mSunSunsetColor = clr(120, 126, 131); - rain.mSunNightColor = clr(50, 62, 101); - rain.mSunDiscSunsetColor = clr(128, 128, 128); - rain.mLandFogDayDepth = 0.8; - rain.mLandFogNightDepth = 0.8; - rain.mWindSpeed = 0.3; - rain.mCloudSpeed = 2; - rain.mGlareView = 0; rain.mRainLoopSoundID = "rain"; - mWeatherSettings["rain"] = rain; + setFallbackWeather(rain,"rain"); Weather overcast; overcast.mCloudTexture = "tx_sky_overcast.dds"; - overcast.mCloudsMaximumPercent = 1.0; - overcast.mTransitionDelta = 0.015; - overcast.mSkySunriseColor = clr(91, 99, 106); - overcast.mSkyDayColor = clr(143, 146, 149); - overcast.mSkySunsetColor = clr(108, 115, 121); - overcast.mSkyNightColor = clr(19, 22, 25); - overcast.mFogSunriseColor = clr(91, 99, 106); - overcast.mFogDayColor = clr(143, 146, 149); - overcast.mFogSunsetColor = clr(108, 115, 121); - overcast.mFogNightColor = clr(19, 22, 25); - overcast.mAmbientSunriseColor = clr(84, 88, 92); - overcast.mAmbientDayColor = clr(93, 96, 105); - overcast.mAmbientSunsetColor = clr(83, 77, 75); - overcast.mAmbientNightColor = clr(57, 60, 66); - overcast.mSunSunriseColor = clr(87, 125, 163); - overcast.mSunDayColor = clr(163, 169, 183); - overcast.mSunSunsetColor = clr(85, 103, 157); - overcast.mSunNightColor = clr(32, 54, 100); - overcast.mSunDiscSunsetColor = clr(128, 128, 128); - overcast.mLandFogDayDepth = 0.7; - overcast.mLandFogNightDepth = 0.7; - overcast.mWindSpeed = 0.2; - overcast.mCloudSpeed = 1.5; - overcast.mGlareView = 0; - mWeatherSettings["overcast"] = overcast; + setFallbackWeather(overcast,"overcast"); Weather ashstorm; ashstorm.mCloudTexture = "tx_sky_ashstorm.dds"; - ashstorm.mCloudsMaximumPercent = 1.0; - ashstorm.mTransitionDelta = 0.035; - ashstorm.mSkySunriseColor = clr(91, 56, 51); - ashstorm.mSkyDayColor = clr(124, 73, 58); - ashstorm.mSkySunsetColor = clr(106, 55, 40); - ashstorm.mSkyNightColor = clr(20, 21, 22); - ashstorm.mFogSunriseColor = clr(91, 56, 51); - ashstorm.mFogDayColor = clr(124, 73, 58); - ashstorm.mFogSunsetColor = clr(106, 55, 40); - ashstorm.mFogNightColor = clr(20, 21, 22); - ashstorm.mAmbientSunriseColor = clr(52, 42, 37); - ashstorm.mAmbientDayColor = clr(75, 49, 41); - ashstorm.mAmbientSunsetColor = clr(48, 39, 35); - ashstorm.mAmbientNightColor = clr(36, 42, 49); - ashstorm.mSunSunriseColor = clr(184, 91, 71); - ashstorm.mSunDayColor = clr(228, 139, 114); - ashstorm.mSunSunsetColor = clr(185, 86, 57); - ashstorm.mSunNightColor = clr(54, 66, 74); - ashstorm.mSunDiscSunsetColor = clr(128, 128, 128); - ashstorm.mLandFogDayDepth = 1.1; - ashstorm.mLandFogNightDepth = 1.2; - ashstorm.mWindSpeed = 0.8; - ashstorm.mCloudSpeed = 7; - ashstorm.mGlareView = 0; ashstorm.mAmbientLoopSoundID = "ashstorm"; - mWeatherSettings["ashstorm"] = ashstorm; + setFallbackWeather(ashstorm,"ashstorm"); Weather blight; blight.mCloudTexture = "tx_sky_blight.dds"; - blight.mCloudsMaximumPercent = 1.0; - blight.mTransitionDelta = 0.04; - blight.mSkySunriseColor = clr(90, 35, 35); - blight.mSkyDayColor = clr(90, 35, 35); - blight.mSkySunsetColor = clr(92, 33, 33); - blight.mSkyNightColor = clr(44, 14, 14); - blight.mFogSunriseColor = clr(90, 35, 35); - blight.mFogDayColor = clr(128, 19, 19); - blight.mFogSunsetColor = clr(92, 33, 33); - blight.mFogNightColor = clr(44, 14, 14); - blight.mAmbientSunriseColor = clr(61, 40, 40); - blight.mAmbientDayColor = clr(79, 54, 54); - blight.mAmbientSunsetColor = clr(61, 40, 40); - blight.mAmbientNightColor = clr(56, 58, 62); - blight.mSunSunriseColor = clr(180, 78, 78); - blight.mSunDayColor = clr(224, 84, 84); - blight.mSunSunsetColor = clr(180, 78, 78); - blight.mSunNightColor = clr(61, 91, 143); - blight.mSunDiscSunsetColor = clr(128, 128, 128); - blight.mLandFogDayDepth = 1.1; - blight.mLandFogNightDepth = 1.2; - blight.mWindSpeed = 0.9; - blight.mCloudSpeed = 9; - blight.mGlareView = 0; blight.mAmbientLoopSoundID = "blight"; - mWeatherSettings["blight"] = blight; + setFallbackWeather(blight,"blight"); /* Weather snow; @@ -502,7 +364,7 @@ void WeatherManager::update(float duration) if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { mCurrentRegion = regionstr; - mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*3600; + mWeatherUpdateTime = mWeatherUpdateTime*3600; std::string weather = "clear"; @@ -681,17 +543,17 @@ void WeatherManager::update(float duration) // pick a random sound int sound = rand() % 4; std::string soundname; - if (sound == 0) soundname = WeatherGlobals::mThunderSoundID0; - else if (sound == 1) soundname = WeatherGlobals::mThunderSoundID1; - else if (sound == 2) soundname = WeatherGlobals::mThunderSoundID2; - else if (sound == 3) soundname = WeatherGlobals::mThunderSoundID3; + if (sound == 0) soundname = mThunderSoundID0; + else if (sound == 1) soundname = mThunderSoundID1; + else if (sound == 2) soundname = mThunderSoundID2; + else if (sound == 3) soundname = mThunderSoundID3; MWBase::Environment::get().getSoundManager()->playSound(soundname, 1.0, 1.0); mThunderSoundDelay = 1000; } mThunderFlash -= duration; if (mThunderFlash > 0) - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / WeatherGlobals::mThunderThreshold ); + mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); else { srand(time(NULL)); @@ -706,11 +568,11 @@ void WeatherManager::update(float duration) mThunderChance += duration*4; // chance increases by 4 percent every second if (mThunderChance >= mThunderChanceNeeded) { - mThunderFlash = WeatherGlobals::mThunderThreshold; + mThunderFlash = mThunderThreshold; - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / WeatherGlobals::mThunderThreshold ); + mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - mThunderSoundDelay = WeatherGlobals::mThunderSoundDelay; + mThunderSoundDelay = 0.25; } } } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 589dff3ebf..3e29be3d96 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -11,106 +11,6 @@ namespace MWRender namespace MWWorld { - /// Global weather manager properties (according to INI) - struct WeatherGlobals - { - /* - [Weather] - EnvReduceColor=255,255,255,255 - LerpCloseColor=037,046,048,255 - BumpFadeColor=230,239,255,255 - AlphaReduce=0.35 - Minimum Time Between Environmental Sounds=1.0 - Maximum Time Between Environmental Sounds=5.0 - Sun Glare Fader Max=0.5 - Sun Glare Fader Angle Max=30.0 - Sun Glare Fader Color=222,095,039 - Timescale Clouds=0 - Precip Gravity=575 - Hours Between Weather Changes=20 - Rain Ripples=1 - Rain Ripple Radius=1024 - Rain Ripples Per Drop=1 - Rain Ripple Scale=0.3 - Rain Ripple Speed=1.0 - Fog Depth Change Speed=3 - Sunrise Time=6 - Sunset Time=18 - Sunrise Duration=2 - Sunset Duration=2 - Sky Pre-Sunrise Time=.5 - Sky Post-Sunrise Time=1 - Sky Pre-Sunset Time=1.5 - Sky Post-Sunset Time=.5 - Ambient Pre-Sunrise Time=.5 - Ambient Post-Sunrise Time=2 - Ambient Pre-Sunset Time=1 - Ambient Post-Sunset Time=1.25 - Fog Pre-Sunrise Time=.5 - Fog Post-Sunrise Time=1 - Fog Pre-Sunset Time=2 - Fog Post-Sunset Time=1 - Sun Pre-Sunrise Time=0 - Sun Post-Sunrise Time=0 - Sun Pre-Sunset Time=1 - Sun Post-Sunset Time=1.25 - Stars Post-Sunset Start=1 - Stars Pre-Sunrise Finish=2 - Stars Fading Duration=2 - Snow Ripples=0 - Snow Ripple Radius=1024 - Snow Ripples Per Flake=1 - Snow Ripple Scale=0.3 - Snow Ripple Speed=1.0 - Snow Gravity Scale=0.1 - Snow High Kill=700 - Snow Low Kill=150 - - - [Moons] - Masser Size=94 - Masser Fade In Start=14 - Masser Fade In Finish=15 - Masser Fade Out Start=7 - Masser Fade Out Finish=10 - Masser Axis Offset=35 - Masser Speed=.5 - Masser Daily Increment=1 - Masser Fade Start Angle=50 - Masser Fade End Angle=40 - Masser Moon Shadow Early Fade Angle=0.5 - Secunda Size=40 - Secunda Fade In Start=14 - Secunda Fade In Finish=15 - Secunda Fade Out Start=7 - Secunda Fade Out Finish=10 - Secunda Axis Offset=50 - Secunda Speed=.6 - Secunda Daily Increment=1.2 - Secunda Fade Start Angle=50 - Secunda Fade End Angle=30 - Secunda Moon Shadow Early Fade Angle=0.5 - Script Color=255,20,20 - */ - - static const float mSunriseTime; - static const float mSunsetTime; - static const float mSunriseDuration; - static const float mSunsetDuration; - - static const float mWeatherUpdateTime; - - // morrowind sets these per-weather, but since they are only used by 'thunderstorm' - // weather setting anyway, we can just as well set them globally - static const float mThunderFrequency; - static const float mThunderThreshold; - static const float mThunderSoundDelay; - static const std::string mThunderSoundID0; - static const std::string mThunderSoundID1; - static const std::string mThunderSoundID2; - static const std::string mThunderSoundID3; - }; - /// Defines the actual weather that results from weather setting (see below), time of day and weather transition struct WeatherResult { @@ -212,7 +112,7 @@ namespace MWWorld class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*); + WeatherManager(MWRender::RenderingManager*,const std::map& fallbackMap); /** * Change the weather in the specified region @@ -241,7 +141,12 @@ namespace MWWorld private: float mHour; int mDay, mMonth; - + std::map mFallback; + std::string getFallback (const std::string& key); + std::string getFallbackS(std::string fall); + float getFallbackF(std::string fall); + Ogre::ColourValue getFallbackClr(std::string fall); + void setFallbackWeather(Weather weather,std::string name); MWRender::RenderingManager* mRendering; std::map mWeatherSettings; @@ -257,14 +162,11 @@ namespace MWWorld bool mFirstUpdate; - float mWeatherUpdateTime; - float mRemainingTransitionTime; float mThunderFlash; float mThunderChance; float mThunderChanceNeeded; - float mThunderSoundDelay; double mTimePassed; // time passed since last update @@ -272,6 +174,18 @@ namespace MWWorld WeatherResult getResult(const Ogre::String& weather); void setWeather(const Ogre::String& weather, bool instant=false); + float mSunriseTime; + float mSunsetTime; + float mSunriseDuration; + float mSunsetDuration; + float mWeatherUpdateTime; + float mThunderFrequency; + float mThunderThreshold; + float mThunderSoundDelay; + std::string mThunderSoundID0; + std::string mThunderSoundID1; + std::string mThunderSoundID2; + std::string mThunderSoundID3; }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 35ea8bbef7..1d1ece78a6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -191,7 +191,7 @@ namespace MWWorld mPhysEngine->setSceneManager(renderer.getScene()); - mWeatherManager = new MWWorld::WeatherManager(mRendering); + mWeatherManager = new MWWorld::WeatherManager(mRendering,fallbackMap); int idx = 0; // NOTE: We might need to reserve one more for the running game / save. From b8c42fde1f81ad0642dc6cb0ec09a5bf376f766d Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Sun, 10 Mar 2013 08:48:54 +0100 Subject: [PATCH 0651/1483] removed chrono from deps, not needed for boost < 1.50 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a7c803e79..280356dc2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,7 +183,7 @@ endif() # find boost without components so we can use Boost_VERSION find_package(Boost REQUIRED) -set(BOOST_COMPONENTS system filesystem program_options thread date_time chrono) +set(BOOST_COMPONENTS system filesystem program_options thread date_time) if (Boost_VERSION LESS 104900) set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE") From 6cef7fb6109fc3eed4da7bc3c65a4c0175ce06fe Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Mar 2013 10:00:20 +0100 Subject: [PATCH 0652/1483] rescale all objects to the range of [0.5, 2] when a cell becomes active --- apps/openmw/mwworld/scene.cpp | 64 ++++++++++++++++++++--------------- apps/openmw/mwworld/scene.hpp | 3 +- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 35024b3079..592fb5c80a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -21,7 +21,7 @@ namespace template void insertCellRefList(MWRender::RenderingManager& rendering, - T& cellRefList, MWWorld::CellStore &cell, MWWorld::PhysicsSystem& physics) + T& cellRefList, MWWorld::CellStore &cell, MWWorld::PhysicsSystem& physics, bool rescale) { if (!cellRefList.mList.empty()) { @@ -31,6 +31,14 @@ namespace for (typename T::List::iterator it = cellRefList.mList.begin(); it != cellRefList.mList.end(); it++) { + if (rescale) + { + if (it->mRef.mScale<0.5) + it->mRef.mScale = 0.5; + else if (it->mRef.mScale>2) + it->mRef.mScale = 2; + } + ++current; if (it->mData.getCount() || it->mData.isEnabled()) @@ -68,7 +76,7 @@ namespace MWWorld { std::cout << "Unloading cell\n"; ListHandles functor; - + (*iter)->forEach(functor); { // silence annoying g++ warning @@ -107,7 +115,9 @@ namespace MWWorld if(result.second) { - insertCell(*cell); + /// \todo rescale depending on the state of a new GMST + insertCell (*cell, true); + mRendering.cellAdded (cell); float verts = ESM::Land::LAND_SIZE; @@ -335,7 +345,7 @@ namespace MWWorld bool loadcell = (mCurrentCell == NULL); if(!loadcell) loadcell = *mCurrentCell != *cell; - + if(!loadcell) { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -347,7 +357,7 @@ namespace MWWorld world->rotateObject(world->getPlayer().getPlayer(), x, y, z); return; } - + std::cout << "Changing to interior\n"; // remove active @@ -383,7 +393,7 @@ namespace MWWorld // adjust fog mRendering.switchToInterior(); mRendering.configureFog(*mCurrentCell); - + // adjust player playerCellChange (mCurrentCell, position); @@ -415,29 +425,29 @@ namespace MWWorld mCellChanged = false; } - void Scene::insertCell (Ptr::CellStore &cell) + void Scene::insertCell (Ptr::CellStore &cell, bool rescale) { // Loop through all references in the cell - insertCellRefList(mRendering, cell.mActivators, cell, *mPhysics); - insertCellRefList(mRendering, cell.mPotions, cell, *mPhysics); - insertCellRefList(mRendering, cell.mAppas, cell, *mPhysics); - insertCellRefList(mRendering, cell.mArmors, cell, *mPhysics); - insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics); - insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics); - insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics); - insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics); - insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics); - insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics); - insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics); - insertCellRefList(mRendering, cell.mItemLists, cell, *mPhysics); - insertCellRefList(mRendering, cell.mLights, cell, *mPhysics); - insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics); - insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics); - insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics); - insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics); - insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics); - insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics); - insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics); + insertCellRefList(mRendering, cell.mActivators, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mPotions, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mAppas, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mArmors, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mItemLists, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mLights, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics, rescale); } void Scene::addObjectToScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 2333a95ab0..dc08d6f9b5 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -56,6 +56,7 @@ namespace MWWorld void playerCellChange (CellStore *cell, const ESM::Position& position, bool adjustPlayerPos = true); + void insertCell (Ptr::CellStore &cell, bool rescale); public: @@ -86,8 +87,6 @@ namespace MWWorld void markCellAsUnchanged(); - void insertCell (Ptr::CellStore &cell); - void update (float duration, bool paused); void addObjectToScene (const Ptr& ptr); From 81338d3b23e05b586b15ed200b70357fb96e479b Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 10 Mar 2013 11:30:24 +0100 Subject: [PATCH 0653/1483] Weather code fixes --- apps/openmw/mwworld/weather.cpp | 93 +++++++++++++++++---------------- apps/openmw/mwworld/weather.hpp | 10 ++-- 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 523f80985b..c3ddab37b1 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -4,7 +4,7 @@ #include #include - +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" @@ -19,7 +19,7 @@ using namespace MWWorld; using namespace MWSound; #define lerp(x, y) (x * (1-factor) + y * factor) -std::string WeatherManager::getFallback (const std::string& key) +const std::string WeatherManager::getFallback (const std::string& key) { std::map::const_iterator it; if((it = mFallback.find(key)) == mFallback.end()) @@ -28,56 +28,57 @@ std::string WeatherManager::getFallback (const std::string& key) } return it->second; } -std::string WeatherManager::getFallbackS(std::string fall) +const std::string WeatherManager::getFallbackString(const std::string fall) { return WeatherManager::getFallback(fall); } -float WeatherManager::getFallbackF(std::string fall) +const float WeatherManager::getFallbackFloat(const std::string fall) { - return atof(getFallbackS(fall).c_str()); + std::string fallback=getFallbackString(fall); + return boost::lexical_cast(fallback); } -ColourValue WeatherManager::getFallbackClr(std::string fall) +const ColourValue WeatherManager::getFallbackColour(const std::string fall) { std::string sum; std::string ret[3]; sum=getFallback(fall); - int j=0; - for(int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); } -void WeatherManager::setFallbackWeather(Weather weather,const std::string name) +const void WeatherManager::setFallbackWeather(Weather weather,const std::string name) { std::string upper=name; upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = getFallbackF("Weather_"+upper+"_Clouds_Maximum_Percent"); - weather.mTransitionDelta = getFallbackF("Weather_"+upper+"_Transition_Delta"); - weather.mSkySunriseColor=getFallbackClr("Weather_"+upper+"_Sky_Sunrise_Color"); - weather.mSkyDayColor = getFallbackClr("Weather_"+upper+"_Sky_Day_Color"); - weather.mSkySunsetColor = getFallbackClr("Weather_"+upper+"_Sky_Sunset_Color"); - weather.mSkyNightColor = getFallbackClr("Weather_"+upper+"_Sky_Night_Color"); - weather.mFogSunriseColor = getFallbackClr("Weather_"+upper+"_Fog_Sunrise_Color"); - weather.mFogDayColor = getFallbackClr("Weather_"+upper+"_Fog_Day_Color"); - weather.mFogSunsetColor = getFallbackClr("Weather_"+upper+"_Fog_Sunset_Color"); - weather.mFogNightColor = getFallbackClr("Weather_"+upper+"_Fog_Night_Color"); - weather.mAmbientSunriseColor = getFallbackClr("Weather_"+upper+"_Ambient_Sunrise_Color"); - weather.mAmbientDayColor = getFallbackClr("Weather_"+upper+"_Ambient_Day_Color"); - weather.mAmbientSunsetColor = getFallbackClr("Weather_"+upper+"_Ambient_Sunset_Color"); - weather.mAmbientNightColor = getFallbackClr("Weather_"+upper+"_Ambient_Night_Color"); - weather.mSunSunriseColor = getFallbackClr("Weather_"+upper+"_Sun_Sunrise_Color"); - weather.mSunDayColor = getFallbackClr("Weather_"+upper+"_Sun_Day_Color"); - weather.mSunSunsetColor = getFallbackClr("Weather_"+upper+"_Sun_Sunset_Color"); - weather.mSunNightColor = getFallbackClr("Weather_"+upper+"_Sun_Night_Color"); - weather.mSunDiscSunsetColor = getFallbackClr("Weather_"+upper+"_Sun_Disc_Sunset_Color"); - weather.mLandFogDayDepth = getFallbackF("Weather_"+upper+"_Land_Fog_Day_Depth"); - weather.mLandFogNightDepth = getFallbackF("Weather_"+upper+"_Land_Fog_Night_Depth"); - weather.mWindSpeed = getFallbackF("Weather_"+upper+"_Wind_Speed"); - weather.mCloudSpeed = getFallbackF("Weather_"+upper+"_Cloud_Speed"); - weather.mGlareView = getFallbackF("Weather_"+upper+"_Glare_View"); + weather.mCloudsMaximumPercent = getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); + weather.mTransitionDelta = getFallbackFloat("Weather_"+upper+"_Transition_Delta"); + weather.mSkySunriseColor=getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); + weather.mSkyDayColor = getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); + weather.mSkySunsetColor = getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); + weather.mSkyNightColor = getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); + weather.mFogSunriseColor = getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); + weather.mFogDayColor = getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); + weather.mFogSunsetColor = getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); + weather.mFogNightColor = getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); + weather.mAmbientSunriseColor = getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); + weather.mAmbientDayColor = getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); + weather.mAmbientSunsetColor = getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); + weather.mAmbientNightColor = getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); + weather.mSunSunriseColor = getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); + weather.mSunDayColor = getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); + weather.mSunSunsetColor = getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); + weather.mSunNightColor = getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); + weather.mSunDiscSunsetColor = getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); + weather.mLandFogDayDepth = getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); + weather.mLandFogNightDepth = getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); + weather.mWindSpeed = getFallbackFloat("Weather_"+upper+"_Wind_Speed"); + weather.mCloudSpeed = getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); + weather.mGlareView = getFallbackFloat("Weather_"+upper+"_Glare_View"); mWeatherSettings[name] = weather; } @@ -89,17 +90,17 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,const std:: { mRendering = rendering; //Globals - mThunderSoundID0 = getFallbackS("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = getFallbackS("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = getFallbackS("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = getFallbackS("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = getFallbackF("Weather_Sunrise_Time"); - mSunsetTime = getFallbackF("Weather_Sunset_Time"); - mSunriseDuration = getFallbackF("Weather_Sunrise_Duration"); - mSunsetDuration = getFallbackF("Weather_Sunset_Duration"); - mWeatherUpdateTime = getFallbackF("Weather_Hours_Between_Weather_Changes"); - mThunderFrequency = getFallbackF("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = getFallbackF("Weather_Thunderstorm_Thunder_Threshold"); + mThunderSoundID0 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = getFallbackFloat("Weather_Sunset_Duration"); + mWeatherUpdateTime = getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderFrequency = getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); mThunderSoundDelay = 0.25; //Weather Weather clear; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 3e29be3d96..ffe103664b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -142,11 +142,11 @@ namespace MWWorld float mHour; int mDay, mMonth; std::map mFallback; - std::string getFallback (const std::string& key); - std::string getFallbackS(std::string fall); - float getFallbackF(std::string fall); - Ogre::ColourValue getFallbackClr(std::string fall); - void setFallbackWeather(Weather weather,std::string name); + const std::string getFallback (const std::string& key); + const std::string getFallbackString(const std::string fall); + const float getFallbackFloat(const std::string fall); + const Ogre::ColourValue getFallbackColour(const std::string fall); + const void setFallbackWeather(Weather weather,const std::string name); MWRender::RenderingManager* mRendering; std::map mWeatherSettings; From bdec87e51b4504e70be16a6ccddc64d5464d7eb4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Mar 2013 11:30:50 +0100 Subject: [PATCH 0654/1483] some cleanup --- apps/openmw/mwworld/weather.cpp | 76 ++++++++++++++++----------------- apps/openmw/mwworld/weather.hpp | 8 ++-- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 6d05df4a2a..052ae4e028 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -19,7 +19,7 @@ using namespace MWWorld; using namespace MWSound; #define lerp(x, y) (x * (1-factor) + y * factor) -std::string WeatherManager::getFallback (const std::string& key) +std::string WeatherManager::getFallback (const std::string& key) const { std::map::const_iterator it; if((it = mFallback.find(key)) == mFallback.end()) @@ -28,34 +28,34 @@ std::string WeatherManager::getFallback (const std::string& key) } return it->second; } -std::string WeatherManager::getFallbackString(const std::string& fall) +std::string WeatherManager::getFallbackString(const std::string& fall) const { - return WeatherManager::getFallback(fall); + return getFallback(fall); } -float WeatherManager::getFallbackFloat(const std::string& fall) +float WeatherManager::getFallbackFloat(const std::string& fall) const { - std::string fallback=getFallbackString(fall); - return boost::lexical_cast(fallback); + std::string fallback=getFallbackString(fall); + return boost::lexical_cast(fallback); } -ColourValue WeatherManager::getFallbackColour(const std::string& fall) +ColourValue WeatherManager::getFallbackColour(const std::string& fall) const { - std::string sum; - std::string ret[3]; - sum=getFallback(fall); - unsigned int j=0; - for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); + std::string sum; + std::string ret[3]; + sum=getFallback(fall); + unsigned int j=0; + for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); } void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { - std::string upper=name; - upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); + std::string upper=name; + upper[0]=toupper(name[0]); + weather.mCloudsMaximumPercent = getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); weather.mTransitionDelta = getFallbackFloat("Weather_"+upper+"_Transition_Delta"); weather.mSkySunriseColor=getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); weather.mSkyDayColor = getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); @@ -89,30 +89,30 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,const std:: mTimePassed(0), mFallback(fallbackMap) { mRendering = rendering; - //Globals - mThunderSoundID0 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = getFallbackFloat("Weather_Sunset_Duration"); - mWeatherUpdateTime = getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mThunderFrequency = getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); - mThunderSoundDelay = 0.25; - //Weather - Weather clear; - clear.mCloudTexture = "tx_sky_clear.dds"; - setFallbackWeather(clear,"clear"); + //Globals + mThunderSoundID0 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = getFallbackFloat("Weather_Sunset_Duration"); + mWeatherUpdateTime = getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderFrequency = getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderSoundDelay = 0.25; + //Weather + Weather clear; + clear.mCloudTexture = "tx_sky_clear.dds"; + setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mCloudTexture = "tx_sky_cloudy.dds"; + cloudy.mCloudTexture = "tx_sky_cloudy.dds"; setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mCloudTexture = "tx_sky_foggy.dds"; + foggy.mCloudTexture = "tx_sky_foggy.dds"; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 3802cd6000..b5bd0e10a0 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -142,10 +142,10 @@ namespace MWWorld float mHour; int mDay, mMonth; std::map mFallback; - std::string getFallback (const std::string& key); - std::string getFallbackString(const std::string& fall); - float getFallbackFloat(const std::string& fall); - Ogre::ColourValue getFallbackColour(const std::string& fall); + std::string getFallback (const std::string& key) const; + std::string getFallbackString(const std::string& fall) const; + float getFallbackFloat(const std::string& fall) const; + Ogre::ColourValue getFallbackColour(const std::string& fall) const; void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; From d5ca00c92782e60d030852c00ab69be3098e25d0 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 10 Mar 2013 12:11:38 +0100 Subject: [PATCH 0655/1483] Another fix --- apps/openmw/mwworld/weather.cpp | 10 +++++----- apps/openmw/mwworld/weather.hpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c3ddab37b1..6d05df4a2a 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -19,7 +19,7 @@ using namespace MWWorld; using namespace MWSound; #define lerp(x, y) (x * (1-factor) + y * factor) -const std::string WeatherManager::getFallback (const std::string& key) +std::string WeatherManager::getFallback (const std::string& key) { std::map::const_iterator it; if((it = mFallback.find(key)) == mFallback.end()) @@ -28,18 +28,18 @@ const std::string WeatherManager::getFallback (const std::string& key) } return it->second; } -const std::string WeatherManager::getFallbackString(const std::string fall) +std::string WeatherManager::getFallbackString(const std::string& fall) { return WeatherManager::getFallback(fall); } -const float WeatherManager::getFallbackFloat(const std::string fall) +float WeatherManager::getFallbackFloat(const std::string& fall) { std::string fallback=getFallbackString(fall); return boost::lexical_cast(fallback); } -const ColourValue WeatherManager::getFallbackColour(const std::string fall) +ColourValue WeatherManager::getFallbackColour(const std::string& fall) { std::string sum; std::string ret[3]; @@ -51,7 +51,7 @@ const ColourValue WeatherManager::getFallbackColour(const std::string fall) } return ColourValue(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); } -const void WeatherManager::setFallbackWeather(Weather weather,const std::string name) +void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { std::string upper=name; upper[0]=toupper(name[0]); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index ffe103664b..3802cd6000 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -142,11 +142,11 @@ namespace MWWorld float mHour; int mDay, mMonth; std::map mFallback; - const std::string getFallback (const std::string& key); - const std::string getFallbackString(const std::string fall); - const float getFallbackFloat(const std::string fall); - const Ogre::ColourValue getFallbackColour(const std::string fall); - const void setFallbackWeather(Weather weather,const std::string name); + std::string getFallback (const std::string& key); + std::string getFallbackString(const std::string& fall); + float getFallbackFloat(const std::string& fall); + Ogre::ColourValue getFallbackColour(const std::string& fall); + void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; std::map mWeatherSettings; From ce91ef36ead190d6e038f75feee31b2ce1f9db56 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sun, 10 Mar 2013 07:49:43 -0500 Subject: [PATCH 0656/1483] Fix for warnings on close, leaves all views open until a decision is made --- apps/opencs/view/doc/view.cpp | 8 +------ apps/opencs/view/doc/view.hpp | 2 -- apps/opencs/view/doc/viewmanager.cpp | 31 ++++++---------------------- apps/opencs/view/doc/viewmanager.hpp | 4 ---- 4 files changed, 7 insertions(+), 38 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 29aa471fdf..51d4a5135c 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -46,8 +46,7 @@ void CSVDoc::View::setupFileMenu() file->addAction(close); QAction *exit = new QAction (tr ("&Exit"), this); - connect (exit, SIGNAL (triggered()), this, SLOT (exitApplication())); - connect (this, SIGNAL (closeAllViews(View *)), &mViewManager, SLOT (closeAllViews(View *))); + connect (exit, SIGNAL (triggered()), QApplication::instance(), SLOT (closeAllWindows())); file->addAction(exit); } @@ -254,8 +253,3 @@ CSVDoc::Operations *CSVDoc::View::getOperations() const { return mOperations; } - -void CSVDoc::View::exitApplication() -{ - emit closeAllViews (this); -} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index d6b6ad4601..92c57fe9ec 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -112,8 +112,6 @@ namespace CSVDoc void addGmstsSubView(); - void exitApplication(); - }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index eb9744c11c..5614aeda44 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -108,16 +108,13 @@ bool CSVDoc::ViewManager::closeRequest (View *view) CSMDoc::Document *document = view->getDocument(); - if (last) - { - //notify user of saving in progress - if ( (document->getState() & CSMDoc::State_Saving) ) - continueWithClose = showSaveInProgressMessageBox (iter); + //notify user of saving in progress + if ( (document->getState() & CSMDoc::State_Saving) ) + continueWithClose = showSaveInProgressMessageBox (iter); - //notify user of unsaved changes and process response - else if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (iter); - } + //notify user of unsaved changes and process response + else if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (iter); if (continueWithClose) { @@ -268,19 +265,3 @@ void CSVDoc::ViewManager::onCloseWarningHandler (int state, CSMDoc::Document *do } } } - -void CSVDoc::ViewManager::closeAllViews (View *lastView) -{ - //forces document views to close in an orderly manner - // the last view closed is the view from which the "Exit" action was triggered - while (mViews.size() > 1) - { - std::vector::iterator iter = mViews.begin(); - - if ((*iter) != lastView) - (*iter)->close(); - else (*(++iter))->close(); - } - - lastView->close(); -} diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 92df13785f..82a8b57330 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -60,10 +60,6 @@ namespace CSVDoc void closeMessageBox(); - public slots: - - void closeAllViews (View *lastView); - private slots: void documentStateChanged (int state, CSMDoc::Document *document); From 1ef682896a2df67cdba9ab5e2e5f3331f0799b72 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 10 Mar 2013 15:03:48 +0100 Subject: [PATCH 0657/1483] Character creation questions import --- apps/openmw/mwgui/charactercreation.cpp | 116 +++++------------------- 1 file changed, 23 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index fbed0a874b..0382c6a1da 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -8,7 +8,7 @@ #include "dialogue.hpp" #include "mode.hpp" #include "inventorywindow.hpp" - +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -17,94 +17,24 @@ namespace { struct Step { - const char* mText; - const char* mButtons[3]; - const char* mSound; + std::string mText; + std::string mButtons[3]; + std::string mSound; ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer }; - static boost::array sGenerateClassSteps = { { - // Question 1 - {"On a clear day you chance upon a strange animal, its legs trapped in a hunter's clawsnare. Judging from the bleeding, it will not survive long.", - {"Draw your dagger, mercifully endings its life with a single thrust.", - "Use herbs from your pack to put it to sleep.", - "Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before."}, - "vo\\misc\\chargen qa1.wav", + Step sGenerateClassSteps(int number) { + MWBase::World *world = MWBase::Environment::get().getWorld(); + number++; + Step step = {world->getFallback("Question_"+boost::lexical_cast(number)+"_Question"), + {world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerOne"), + world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), + world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, + "vo\\misc\\chargen qa"+boost::lexical_cast(number)+".wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 2 - {"One Summer afternoon your father gives you a choice of chores.", - {"Work in the forge with him casting iron for a new plow.", - "Gather herbs for your mother who is preparing dinner.", - "Go catch fish at the stream using a net and line."}, - "vo\\misc\\chargen qa2.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 3 - {"Your cousin has given you a very embarrassing nickname and, even worse, likes to call you it in front of your friends. You asked him to stop, but he finds it very amusing to watch you blush.", - {"Beat up your cousin, then tell him that if he ever calls you that nickname again, you will bloody him worse than this time.", - "Make up a story that makes your nickname a badge of honor instead of something humiliating.", - "Make up an even more embarrassing nickname for him and use it constantly until he learns his lesson."}, - "vo\\misc\\chargen qa3.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 4 - {"There is a lot of heated discussion at the local tavern over a grouped of people called 'Telepaths'. They have been hired by certain City-State kings. Rumor has it these Telepaths read a person's mind and tell their lord whether a follower is telling the truth or not.", - {"This is a terrible practice. A person's thoughts are his own and no one, not even a king, has the right to make such an invasion into another human's mind.", - "Loyal followers to the king have nothing to fear from a Telepath. It is important to have a method of finding assassins and spies before it is too late.", - "In these times, it is a necessary evil. Although you do not necessarily like the idea, a Telepath could have certain advantages during a time of war or in finding someone innocent of a crime."}, - "vo\\misc\\chargen qa4.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 5 - {"Your mother sends you to the market with a list of goods to buy. After you finish you find that by mistake a shopkeeper has given you too much money back in exchange for one of the items.", - {"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?", - "Decide to put the extra money to good use and purchase items that would help your family?", - "Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?"}, - "vo\\misc\\chargen qa5.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 6 - {"While in the market place you witness a thief cut a purse from a noble. Even as he does so, the noble notices and calls for the city guards. In his haste to get away, the thief drops the purse near you. Surprisingly no one seems to notice the bag of coins at your feet.", - {"Pick up the bag and signal to the guard, knowing that the only honorable thing to do is return the money to its rightful owner.", - "Leave the bag there, knowing that it is better not to get involved.", - "Pick up the bag and pocket it, knowing that the extra windfall will help your family in times of trouble."}, - "vo\\misc\\chargen qa6.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 7 - {"Your father sends you on a task which you loathe, cleaning the stables. On the way there, pitchfork in hand, you run into your friend from the homestead near your own. He offers to do it for you, in return for a future favor of his choosing.", - {"Decline his offer, knowing that your father expects you to do the work, and it is better not to be in debt.", - "Ask him to help you, knowing that two people can do the job faster than one, and agree to help him with one task of his choosing in the future.", - "Accept his offer, reasoning that as long as the stables are cleaned, it matters not who does the cleaning."}, - "vo\\misc\\chargen qa7.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 8 - {"Your mother asks you to help fix the stove. While you are working, a very hot pipe slips its mooring and falls towards her.", - {"Position yourself between the pipe and your mother.", - "Grab the hot pipe and try to push it away.", - "Push your mother out of the way."}, - "vo\\misc\\chargen qa8.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 9 - {"While in town the baker gives you a sweetroll. Delighted, you take it into an alley to enjoy only to be intercepted by a gang of three other kids your age. The leader demands the sweetroll, or else he and his friends will beat you and take it.", - {"Drop the sweetroll and step on it, then get ready for the fight.", - "Give him the sweetroll now without argument, knowing that later this afternoon you will have all your friends with you and can come and take whatever he owes you.", - "Act like you're going to give him the sweetroll, but at the last minute throw it in the air, hoping that they'll pay attention to it long enough for you to get a shot in on the leader."}, - "vo\\misc\\chargen qa9.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - }, - // Question 10 - {"Entering town you find that you are witness to a very well-dressed man running from a crowd. He screams to you for help. The crowd behind him seem very angry.", - {"Rush to the town's aid immediately, despite your lack of knowledge of the circumstances.", - "Stand aside and allow the man and the mob to pass, realizing it is probably best not to get involved.", - "Rush to the man's aid immediately, despite your lack of knowledge of the circumstances."}, - "vo\\misc\\chargen qa10.wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} - } - } }; + }; + return step; + } struct ClassPoint { @@ -638,7 +568,7 @@ void CharacterCreation::onClassQuestionChosen(int _index) return; } - ESM::Class::Specialization specialization = sGenerateClassSteps[mGenerateClassStep].mSpecializations[_index]; + ESM::Class::Specialization specialization = sGenerateClassSteps(mGenerateClassStep).mSpecializations[_index]; if (specialization == ESM::Class::Stealth) ++mGenerateClassSpecializations[0]; else if (specialization == ESM::Class::Combat) @@ -651,7 +581,7 @@ void CharacterCreation::onClassQuestionChosen(int _index) void CharacterCreation::showClassQuestionDialog() { - if (mGenerateClassStep == sGenerateClassSteps.size()) + if (mGenerateClassStep == 10) { static boost::array classes = { { {"Acrobat", {6, 2, 2}}, @@ -718,7 +648,7 @@ void CharacterCreation::showClassQuestionDialog() return; } - if (mGenerateClassStep > sGenerateClassSteps.size()) + if (mGenerateClassStep > 10) { mWM->popGuiMode(); mWM->pushGuiMode(GM_Class); @@ -731,15 +661,15 @@ void CharacterCreation::showClassQuestionDialog() mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM); InfoBoxDialog::ButtonList buttons; - mGenerateClassQuestionDialog->setText(sGenerateClassSteps[mGenerateClassStep].mText); - buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[0]); - buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[1]); - buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[2]); + mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[0]); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[1]); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[2]); mGenerateClassQuestionDialog->setButtons(buttons); mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); mGenerateClassQuestionDialog->setVisible(true); - MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps[mGenerateClassStep].mSound); + MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); } void CharacterCreation::onGenerateClassBack() From 04e99ee9d6dc9cbd6653c10ac5f469ff4641b36f Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 10 Mar 2013 15:15:33 +0100 Subject: [PATCH 0658/1483] Character creation struct consts --- apps/openmw/mwgui/charactercreation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 0382c6a1da..ba0f6004a4 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -17,10 +17,10 @@ namespace { struct Step { - std::string mText; - std::string mButtons[3]; - std::string mSound; - ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer + const std::string mText; + const std::string mButtons[3]; + const std::string mSound; + const ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer }; Step sGenerateClassSteps(int number) { From 93de570f9a5f43b7d87826b1457cca52b7465143 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 10 Mar 2013 15:58:29 +0100 Subject: [PATCH 0659/1483] Moved specializations out of step --- apps/openmw/mwgui/charactercreation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index ba0f6004a4..b98fd2bd9f 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -20,9 +20,10 @@ namespace const std::string mText; const std::string mButtons[3]; const std::string mSound; - const ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer }; + const ESM::Class::Specialization mSpecializations[3]={ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}; // The specialization for each answer + Step sGenerateClassSteps(int number) { MWBase::World *world = MWBase::Environment::get().getWorld(); number++; @@ -30,8 +31,7 @@ namespace {world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerOne"), world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, - "vo\\misc\\chargen qa"+boost::lexical_cast(number)+".wav", - {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} + "vo\\misc\\chargen qa"+boost::lexical_cast(number)+".wav" }; return step; } @@ -568,7 +568,7 @@ void CharacterCreation::onClassQuestionChosen(int _index) return; } - ESM::Class::Specialization specialization = sGenerateClassSteps(mGenerateClassStep).mSpecializations[_index]; + ESM::Class::Specialization specialization = mSpecializations[_index]; if (specialization == ESM::Class::Stealth) ++mGenerateClassSpecializations[0]; else if (specialization == ESM::Class::Combat) From bbc4c23f7e184782eec35bface3e0d10df182dd1 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 10 Mar 2013 15:07:22 +0000 Subject: [PATCH 0660/1483] AITravel now works correctly on exterior cells. As long as NPC don't try to leave cell, it's ok. --- apps/openmw/mwmechanics/aitravel.cpp | 31 ++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 9d41a080c7..09b0efad9c 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -53,7 +53,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) i0 = i; } } - + std::cout << "distance:: " << m << "\n"; return i0; } @@ -135,14 +135,16 @@ std::list getPath(PointID start,PointID end,PathGridGraph return shortest_path; } -PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid) +PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; for(int i = 0;imPoints.size();i++) { PointID pID = boost::add_vertex(graph); - graph[pID] = pathgrid->mPoints[i]; + graph[pID].mX = pathgrid->mPoints[i].mX + xCell; + graph[pID].mY = pathgrid->mPoints[i].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[i].mZ; } for(int i = 0;imEdges.size();i++) @@ -165,17 +167,26 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - ESM::Position pos = actor.getRefData().getPosition(); + ESM::Position pos = actor.getRefData().getPosition(); + //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } - PathGridGraph graph = buildGraph(pathgrid); + int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); + int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); + + PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); mPath = getPath(start,end,graph); + if(mPath.empty()) std::cout << "graph doesn't find any way..."; ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; @@ -185,6 +196,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(mPath.empty()) { + std::cout << "pathc empty"; MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } @@ -195,6 +207,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) if(mPath.empty()) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + std::cout << "emptypath!"; return true; } nextPoint = *mPath.begin(); @@ -205,8 +218,8 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + return false; - //return true; } int MWMechanics::AiTravel::getTypeId() const From dad66cd9684d0ca15fff80081ffc45d12f50b520 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Mar 2013 17:34:05 +0100 Subject: [PATCH 0661/1483] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index d1e85c6904..f06377500a 100644 --- a/credits.txt +++ b/credits.txt @@ -43,6 +43,7 @@ Mark Siewert (mark76) Manuel Edelmann (vorenon) Michael Mc Donnell Michael Papageorgiou (werdanith) +Michał Bień (Glorf) Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) Nolan Poe (nopoe) From 52e5dcc7f0e5ea3af828d230c8e39a6648d1bcbf Mon Sep 17 00:00:00 2001 From: pvdk Date: Sun, 10 Mar 2013 21:12:26 +0100 Subject: [PATCH 0662/1483] Some fixes to the way data paths are saved and settings are handled --- apps/launcher/maindialog.cpp | 21 ++++++++++----------- apps/launcher/maindialog.hpp | 2 +- apps/launcher/settings/gamesettings.hpp | 5 ----- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 6a3965cc91..5d11421d0f 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -213,8 +213,6 @@ bool MainDialog::showFirstRunDialog() return false; // Re-read the game settings - mGameSettings.clear(); - if (!setupGameSettings()) return false; @@ -389,7 +387,7 @@ bool MainDialog::setupGameSettings() QFileInfo info(selectedFile); // Add the new dir to the settings file and to the data dir container - mGameSettings.setValue(QString("data"), info.absolutePath()); + mGameSettings.setMultiValue(QString("data"), info.absolutePath()); mGameSettings.addDataDir(info.absolutePath()); } @@ -478,7 +476,7 @@ void MainDialog::saveSettings() } -void MainDialog::writeSettings() +bool MainDialog::writeSettings() { // Now write all config files saveSettings(); @@ -498,7 +496,7 @@ void MainDialog::writeSettings() Please make sure you have the right permissions \ and try again.
").arg(userPath)); msgBox.exec(); - return; + return false; } } @@ -515,7 +513,7 @@ void MainDialog::writeSettings() Please make sure you have the right permissions \ and try again.
").arg(file.fileName())); msgBox.exec(); - return; + return false; } QTextStream stream(&file); @@ -537,7 +535,7 @@ void MainDialog::writeSettings() Please make sure you have the right permissions \ and try again.
").arg(file.fileName())); msgBox.exec(); - return; + return false; } stream.setDevice(&file); @@ -559,7 +557,7 @@ void MainDialog::writeSettings() Please make sure you have the right permissions \ and try again.
").arg(file.fileName())); msgBox.exec(); - return; + return false; } stream.setDevice(&file); @@ -567,19 +565,20 @@ void MainDialog::writeSettings() mLauncherSettings.writeFile(stream); file.close(); + + return true; } void MainDialog::closeEvent(QCloseEvent *event) { - saveSettings(); writeSettings(); event->accept(); } void MainDialog::play() { - saveSettings(); - writeSettings(); + if (!writeSettings()) + qApp->quit(); // Launch the game detached startProgram(QString("openmw"), true); diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 643206ab6c..7e818a74ab 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -45,7 +45,7 @@ private: void loadSettings(); void saveSettings(); - void writeSettings(); + bool writeSettings(); inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); } bool startProgram(const QString &name, const QStringList &arguments, bool detached = false); diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index 6c296711f8..7a17ef9af0 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -40,11 +40,6 @@ public: mSettings.remove(key); } - inline void clear() - { - mSettings.clear(); - } - inline QStringList getDataDirs() { return mDataDirs; } inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } inline QString getDataLocal() {return mDataLocal; } From 091c569fbeafd9d0399f1500b3748112bfb2285f Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 11 Mar 2013 01:20:30 +0100 Subject: [PATCH 0663/1483] Fixed issue with the combobox dropdown looking weird --- apps/launcher/playpage.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index 27b7846ddd..d6d25d71d0 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -6,13 +6,12 @@ PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { setupUi(this); - // Hacks to get the stylesheet look properly on different platforms + // Hacks to get the stylesheet look properly +#ifdef Q_OS_MAC QPlastiqueStyle *style = new QPlastiqueStyle; - QFont font = QApplication::font(); - font.setPointSize(12); // Fixes problem with overlapping items - profilesComboBox->setStyle(style); - profilesComboBox->setFont(font); +#endif + profilesComboBox->setView(new QListView()); connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int))); connect(playButton, SIGNAL(clicked()), this, SLOT(slotPlayClicked())); From fc1940257ad0b69d68f758051e4c20df2633bd48 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 11 Mar 2013 01:23:24 +0100 Subject: [PATCH 0664/1483] Fixed issue with new profile dialog being too small --- apps/launcher/utils/textinputdialog.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/launcher/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp index 011e51bf25..a4b36b95ea 100644 --- a/apps/launcher/utils/textinputdialog.cpp +++ b/apps/launcher/utils/textinputdialog.cpp @@ -1,14 +1,14 @@ +#include "textinputdialog.hpp" + #include #include #include -#include #include #include +#include #include -#include "textinputdialog.hpp" - TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) : QDialog(parent) { @@ -38,7 +38,6 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid Q_UNUSED(title); #endif - setMaximumHeight(height()); setOkButtonEnabled(false); setModal(true); From 5e13614e084aea5ce7a48f2056cd8a5f03fdfc04 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 11 Mar 2013 01:34:12 +0100 Subject: [PATCH 0665/1483] Improved appearance of combobox and when using dark color themes --- files/ui/mainwindow.ui | 16 ++++------------ files/ui/playpage.ui | 13 ++++++------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/files/ui/mainwindow.ui b/files/ui/mainwindow.ui index 4e1a7854d6..8143fa24df 100644 --- a/files/ui/mainwindow.ui +++ b/files/ui/mainwindow.ui @@ -2,25 +2,17 @@ MainWindow - - - 0 - 0 - 575 - 575 - - 575 - 575 + 525 OpenMW Launcher - + :/images/openmw.png:/images/openmw.png @@ -42,7 +34,7 @@ #iconWidget { background-image: url(":/images/openmw-header.png"); - background-color: white; + background-color: palette(base); background-repeat: no-repeat; background-attachment: scroll; background-position: right; @@ -74,7 +66,7 @@ - + diff --git a/files/ui/playpage.ui b/files/ui/playpage.ui index ccd17f519c..6b8b66b208 100644 --- a/files/ui/playpage.ui +++ b/files/ui/playpage.ui @@ -58,6 +58,7 @@ font-size: 12pt; font-family: "EB Garamond", "EB Garamond 08"; + color: black; } #profilesComboBox::drop-down { @@ -81,11 +82,10 @@ left: 1px; } + #profilesComboBox QAbstractItemView { - border: 2px solid lightgray; - border-radius: 5px; -} -
+ border: 0px; +}
@@ -95,6 +95,7 @@ #profileLabel { font-size: 18pt; font-family: "EB Garamond", "EB Garamond 08"; + color: black; }
@@ -185,8 +186,6 @@
- - - + From b4d408af5dd62a093e6983a03d8e55e79e0c86d4 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 11 Mar 2013 01:48:01 +0100 Subject: [PATCH 0666/1483] Added actions to datafiles.ui and implemented them in the launcher --- apps/launcher/datafilespage.cpp | 97 ++++++++++----------------------- apps/launcher/datafilespage.hpp | 25 ++------- files/ui/datafilespage.ui | 38 +++++++++++++ 3 files changed, 71 insertions(+), 89 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 90cdd29425..444d05b2a0 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -17,19 +17,6 @@ #include "utils/textinputdialog.hpp" - -//sort QModelIndexList ascending -bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2) -{ - return index1.row() >= index2.row(); -} - -//sort QModelIndexList descending -bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) -{ - return index1.row() <= index2.row(); -} - DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent) : mCfgMgr(cfg) , mGameSettings(gameSettings) @@ -121,35 +108,15 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam void DataFilesPage::createActions() { - // Refresh the plugins - QAction *refreshAction = new QAction(tr("Refresh"), this); - refreshAction->setShortcut(QKeySequence(tr("F5"))); - connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); - // We can't create actions inside the .ui file - mNewProfileAction = new QAction(QIcon::fromTheme("document-new"), tr("&New Profile"), this); - mNewProfileAction->setToolTip(tr("New Profile")); - mNewProfileAction->setShortcut(QKeySequence(tr("Ctrl+N"))); - connect(mNewProfileAction, SIGNAL(triggered()), this, SLOT(newProfile())); - - mDeleteProfileAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete Profile"), this); - mDeleteProfileAction->setToolTip(tr("Delete Profile")); - connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); - - // Add the newly created actions to the toolbuttons - newProfileButton->setDefaultAction(mNewProfileAction); - deleteProfileButton->setDefaultAction(mDeleteProfileAction); + // Add the actions to the toolbuttons + newProfileButton->setDefaultAction(newProfileAction); + deleteProfileButton->setDefaultAction(deleteProfileAction); // Context menu actions - mCheckAction = new QAction(tr("Check Selection"), this); - connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check())); - - mUncheckAction = new QAction(tr("Uncheck Selection"), this); - connect(mUncheckAction, SIGNAL(triggered()), this, SLOT(uncheck())); - mContextMenu = new QMenu(this); - mContextMenu->addAction(mCheckAction); - mContextMenu->addAction(mUncheckAction); + mContextMenu->addAction(checkAction); + mContextMenu->addAction(uncheckAction); } void DataFilesPage::setupDataFiles() @@ -184,6 +151,8 @@ void DataFilesPage::setupDataFiles() profilesComboBox->addItem(QString("Default")); if (profile.isEmpty() || profile == QLatin1String("Default")) { + deleteProfileAction->setEnabled(false); + profilesComboBox->setEditEnabled(false); profilesComboBox->setCurrentIndex(profilesComboBox->findText(QString("Default"))); } else { profilesComboBox->setEditEnabled(true); @@ -257,15 +226,6 @@ void DataFilesPage::saveSettings() } -void DataFilesPage::newProfile() -{ - if (mNewProfileDialog->exec() == QDialog::Accepted) { - QString profile = mNewProfileDialog->lineEdit()->text(); - profilesComboBox->addItem(profile); - profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile)); - } -} - void DataFilesPage::updateOkButton(const QString &text) { // We do this here because we need the profiles combobox text @@ -331,7 +291,16 @@ int DataFilesPage::profilesComboBoxIndex() return profilesComboBox->currentIndex(); } -void DataFilesPage::deleteProfile() +void DataFilesPage::on_newProfileAction_triggered() +{ + if (mNewProfileDialog->exec() == QDialog::Accepted) { + QString profile = mNewProfileDialog->lineEdit()->text(); + profilesComboBox->addItem(profile); + profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile)); + } +} + +void DataFilesPage::on_deleteProfileAction_triggered() { QString profile = profilesComboBox->currentText(); @@ -358,7 +327,7 @@ void DataFilesPage::deleteProfile() } } -void DataFilesPage::check() +void DataFilesPage::on_checkAction_triggered() { if (pluginsTable->hasFocus()) setPluginsCheckstates(Qt::Checked); @@ -368,7 +337,7 @@ void DataFilesPage::check() } -void DataFilesPage::uncheck() +void DataFilesPage::on_uncheckAction_triggered() { if (pluginsTable->hasFocus()) setPluginsCheckstates(Qt::Unchecked); @@ -377,14 +346,6 @@ void DataFilesPage::uncheck() setMastersCheckstates(Qt::Unchecked); } -void DataFilesPage::refresh() -{ -// mDataFilesModel->sort(0); - - // Refresh the plugins table - pluginsTable->scrollToTop(); -} - void DataFilesPage::setMastersCheckstates(Qt::CheckState state) { if (!mastersTable->selectionModel()->hasSelection()) { @@ -476,10 +437,10 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre { // Prevent the deletion of the default profile if (current == QLatin1String("Default")) { - mDeleteProfileAction->setEnabled(false); + deleteProfileAction->setEnabled(false); profilesComboBox->setEditEnabled(false); } else { - mDeleteProfileAction->setEnabled(true); + deleteProfileAction->setEnabled(true); profilesComboBox->setEditEnabled(true); } @@ -533,8 +494,8 @@ void DataFilesPage::showContextMenu(const QPoint &point) QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes(); // Show the check/uncheck actions depending on the state of the selected items - mUncheckAction->setEnabled(false); - mCheckAction->setEnabled(false); + uncheckAction->setEnabled(false); + checkAction->setEnabled(false); foreach (const QModelIndex &index, indexes) { @@ -548,8 +509,8 @@ void DataFilesPage::showContextMenu(const QPoint &point) return; (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mUncheckAction->setEnabled(true) - : mCheckAction->setEnabled(true); + ? uncheckAction->setEnabled(true) + : checkAction->setEnabled(true); } // Show menu @@ -564,8 +525,8 @@ void DataFilesPage::showContextMenu(const QPoint &point) QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes(); // Show the check/uncheck actions depending on the state of the selected items - mUncheckAction->setEnabled(false); - mCheckAction->setEnabled(false); + uncheckAction->setEnabled(false); + checkAction->setEnabled(false); foreach (const QModelIndex &index, indexes) { @@ -578,8 +539,8 @@ void DataFilesPage::showContextMenu(const QPoint &point) return; (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mUncheckAction->setEnabled(true) - : mCheckAction->setEnabled(true); + ? uncheckAction->setEnabled(true) + : checkAction->setEnabled(true); } mContextMenu->exec(globalPos); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 301abf59bf..a0b0293309 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -48,11 +48,10 @@ public slots: void updateViews(); // Action slots - void newProfile(); - void deleteProfile(); - void check(); - void uncheck(); - void refresh(); + void on_newProfileAction_triggered(); + void on_deleteProfileAction_triggered(); + void on_checkAction_triggered(); + void on_uncheckAction_triggered(); private slots: void slotCurrentIndexChanged(int index); @@ -65,23 +64,7 @@ private: QSortFilterProxyModel *mFilterProxyModel; -// QTableView *mMastersTable; -// QTableView *mPluginsTable; - - -// QToolBar *mProfileToolBar; QMenu *mContextMenu; -// QSplitter *mSplitter; - - QAction *mNewProfileAction; - QAction *mDeleteProfileAction; - QAction *mCheckAction; - QAction *mUncheckAction; - -// QAction *mMoveUpAction; -// QAction *mMoveDownAction; -// QAction *mMoveTopAction; -// QAction *mMoveBottomAction; Files::ConfigurationManager &mCfgMgr; diff --git a/files/ui/datafilespage.ui b/files/ui/datafilespage.ui index 044817fb40..5c498d4d57 100644 --- a/files/ui/datafilespage.ui +++ b/files/ui/datafilespage.ui @@ -67,6 +67,9 @@ + + true + 0 @@ -107,6 +110,41 @@ + + + + + + New Profile + + + New Profile + + + Ctrl+N + + + + + + + + Delete Profile + + + Delete Profile + + + + + Check Selection + + + + + Uncheck Selection + +
From 64c5af314d201683d76074609ebf62145f407cbd Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 11 Mar 2013 01:53:54 +0100 Subject: [PATCH 0667/1483] Removed grayish pixel from the clear button, looks weird with dark colors --- files/launcher/images/clear.png | Bin 644 -> 590 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/files/launcher/images/clear.png b/files/launcher/images/clear.png index 6c4b83b7ac6e451f461973dac0c9a6c53dedef25..0e72a65ea8696b60c68bf977e928f2b9a6e038a2 100644 GIT binary patch delta 248 zcmV*eX;?dGZh;R{&@B>6e|Bn4Wlg83pQ4w1=;K}o4`7K$Lgn7)~@O;mD9YJ!!XG?34y zsi&i@?Vp;O;;*JG4pJd1C$C@>6(18HZ6P56HbYoSGCVfSJ~lKqLPZi{i=dKWu%&@r yh?ABS)E)flruNS6F81a!Fqbki%0d7Uz5)RKjT=wcK1w$L0000f=GbH|(^1_+TrFGh$L7 z5%Z!OZ(LQXwtw6g1bNBX0q`}^OtN%%Jjq^LAz}m|@kc_z;FKhvQ;$;%fTy-tZHdG6 zbUo&DI=pd|2L1NDDX-5vmmVK1xg);J$11Bvz<@7?)SIq0yRB;01PV=Prik&|3tVy> U7`-bGF8}}l07*qoM6N<$g8y)X?f?J) From 96b62940b399e4f88fb9c415d923a8506e3581af Mon Sep 17 00:00:00 2001 From: graffy76 Date: Mon, 11 Mar 2013 06:38:27 -0500 Subject: [PATCH 0668/1483] Fixes docked subviews becoming tabbed and application closure when closing one of several views. --- apps/opencs/view/doc/view.cpp | 4 +++- apps/opencs/view/doc/viewmanager.cpp | 22 +++++++++++++--------- apps/opencs/view/doc/viewmanager.hpp | 4 +++- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 51d4a5135c..dfbd92a609 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -131,10 +131,12 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - setDockOptions (QMainWindow::AllowNestedDocks); + // setDockOptions (QMainWindow::AllowNestedDocks); resize (300, 300); /// \todo get default size from settings and set reasonable minimal size + mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); + setCentralWidget (&mSubViewWindow); mOperations = new Operations; diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 5614aeda44..83ace49387 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include void CSVDoc::ViewManager::updateIndices() { @@ -44,6 +46,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); + connect (this, SIGNAL (exitApplication()), QApplication::instance(), SLOT (closeAllWindows())); + } CSVDoc::ViewManager::~ViewManager() @@ -143,7 +147,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::i bool retVal = true; connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); - connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); mUserWarned = true; int response = messageBox.exec(); @@ -161,13 +165,13 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::i case QMessageBox::Discard: - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); break; case QMessageBox::Cancel: //disconnect to prevent unintended view closures - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); retVal = false; break; @@ -195,7 +199,7 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::ite bool retVal = true; //Connections shut down message box if operation ends before user makes a decision. - connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); //set / clear the user warned flag to indicate whether or not the message box is currently active. @@ -216,7 +220,7 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::ite else if (messageBox.clickedButton() == closeButton) { //disconnect to avoid segmentation fault - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); (*viewIter)->abortOperation(CSMDoc::State_Saving); mCloseMeOnSaveStateChange = mViews.end(); } @@ -226,7 +230,7 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::ite //abort shutdown, allow save to complete //disconnection to prevent unintended view closures mCloseMeOnSaveStateChange = mViews.end(); - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); retVal = false; } @@ -247,7 +251,7 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, (*iter)->updateProgress (current, max, type, threads); } -void CSVDoc::ViewManager::onCloseWarningHandler (int state, CSMDoc::Document *document) +void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *document) { if ( !(state & CSMDoc::State_Saving) ) { @@ -257,10 +261,10 @@ void CSVDoc::ViewManager::onCloseWarningHandler (int state, CSMDoc::Document *do emit closeMessageBox(); //otherwise, the user has closed the message box before the save operation ended. - //close the view + //exit the application else if (mCloseMeOnSaveStateChange!=mViews.end()) { - (*mCloseMeOnSaveStateChange)->close(); + emit exitApplication(); mCloseMeOnSaveStateChange = mViews.end(); } } diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 82a8b57330..b77e5f5758 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -60,13 +60,15 @@ namespace CSVDoc void closeMessageBox(); + void exitApplication(); + private slots: void documentStateChanged (int state, CSMDoc::Document *document); void progress (int current, int max, int type, int threads, CSMDoc::Document *document); - void onCloseWarningHandler(int state, CSMDoc::Document* document); + void onExitWarningHandler(int state, CSMDoc::Document* document); }; } From 64d517dd796a5f07406f909ee25fca81008c920e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Mar 2013 14:42:49 +0100 Subject: [PATCH 0669/1483] removed unused file type information from esm component --- apps/esmtool/esmtool.cpp | 4 ---- components/esm/esmcommon.hpp | 4 ++-- components/esm/esmreader.cpp | 24 ------------------------ components/esm/esmreader.hpp | 3 --- components/esm/esmwriter.cpp | 16 +++------------- components/esm/esmwriter.hpp | 4 +--- 6 files changed, 6 insertions(+), 49 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 3c9476d7a2..b243917be9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -23,7 +23,6 @@ struct ESMData std::string author; std::string description; int version; - int type; ESM::ESMReader::MasterList masters; std::deque mRecords; @@ -284,8 +283,6 @@ int load(Arguments& info) info.data.author = esm.getAuthor(); info.data.description = esm.getDesc(); info.data.masters = esm.getMasters(); - info.data.version = esm.getVer(); - info.data.type = esm.getType(); if (!quiet) { @@ -430,7 +427,6 @@ int clone(Arguments& info) esm.setAuthor(info.data.author); esm.setDescription(info.data.description); esm.setVersion(info.data.version); - esm.setType(info.data.type); for (ESM::ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) esm.addMaster(it->name, it->size); diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 335d123378..f5ddf62802 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -41,7 +41,7 @@ union NAME_T { char name[LEN]; int32_t val; - + bool operator==(const char *str) const { for(int i=0; i mBuffer; - SaveData mSaveData; MasterList mMasters; std::vector *mGlobalReaderList; ToUTF8::Utf8Encoder* mEncoder; diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index b9dd5b57b6..faceeeaa6f 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -17,16 +17,6 @@ void ESMWriter::setVersion(int ver) m_header.version = ver; } -int ESMWriter::getType() -{ - return m_header.type; -} - -void ESMWriter::setType(int type) -{ - m_header.type = type; -} - void ESMWriter::setAuthor(const std::string& auth) { strncpy((char*)&m_header.author, auth.c_str(), 32); @@ -86,7 +76,7 @@ void ESMWriter::close() void ESMWriter::startRecord(const std::string& name, uint32_t flags) { m_recordCount++; - + writeName(name); RecordData rec; rec.name = name; @@ -109,7 +99,7 @@ void ESMWriter::startSubRecord(const std::string& name) rec.size = 0; writeT(0); // Size goes here m_records.push_back(rec); - + assert(m_records.back().size == 0); } @@ -118,7 +108,7 @@ void ESMWriter::endRecord(const std::string& name) RecordData rec = m_records.back(); assert(rec.name == name); m_records.pop_back(); - + m_stream->seekp(rec.position); count = false; diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index 94e173b4ce..f488cce3e1 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -22,8 +22,6 @@ class ESMWriter public: int getVersion(); void setVersion(int ver); - int getType(); - void setType(int type); void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8? void setAuthor(const std::string& author); void setDescription(const std::string& desc); @@ -80,7 +78,7 @@ public: { write((char*)&data, size); } - + void startRecord(const std::string& name, uint32_t flags); void startSubRecord(const std::string& name); void endRecord(const std::string& name); From 2e1a1fd11a4cd0583c2c507eb1aaa203444dbd13 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Mar 2013 16:30:47 +0100 Subject: [PATCH 0670/1483] removing some remains of the removed GMST fixing feature --- apps/esmtool/esmtool.cpp | 3 +-- components/esm/esmcommon.hpp | 11 ----------- components/esm/esmreader.cpp | 12 ------------ components/esm/esmreader.hpp | 2 -- 4 files changed, 1 insertion(+), 27 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index b243917be9..8d060cbd22 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -288,8 +288,7 @@ int load(Arguments& info) { std::cout << "Author: " << esm.getAuthor() << std::endl << "Description: " << esm.getDesc() << std::endl - << "File format version: " << esm.getFVer() << std::endl - << "Special flag: " << esm.getSpecial() << std::endl; + << "File format version: " << esm.getFVer() << std::endl; ESM::ESMReader::MasterList m = esm.getMasters(); if (!m.empty()) { diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index f5ddf62802..af83ad816a 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -21,17 +21,6 @@ enum FileType FT_ESS = 32 // Savegame }; -// Used to mark special files. The original ESM files are given -// special treatment in a few places, most noticably in loading and -// filtering out "dirtly" GMST entries correctly. -enum SpecialFile - { - SF_Other, - SF_Morrowind, - SF_Tribunal, - SF_Bloodmoon - }; - /* A structure used for holding fixed-length strings. In the case of LEN=4, it can be more efficient to match the string as a 32 bit number, therefore the struct is implemented as a union with an int. diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index edd047d92d..98c598eb9a 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -51,18 +51,6 @@ void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) mEsm = _esm; mCtx.filename = name; mCtx.leftFile = mEsm->size(); - - // Flag certain files for special treatment, based on the file - // name. - const char *cstr = mCtx.filename.c_str(); - if (iends(cstr, "Morrowind.esm")) - mSpf = SF_Morrowind; - else if (iends(cstr, "Tribunal.esm")) - mSpf = SF_Tribunal; - else if (iends(cstr, "Bloodmoon.esm")) - mSpf = SF_Bloodmoon; - else - mSpf = SF_Other; } void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 94bf0f3d33..dd7809fb3c 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -38,7 +38,6 @@ public: int getVer() const { return mCtx.header.version; } float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } - int getSpecial() const { return mSpf; } const std::string getAuthor() const { return mCtx.header.author.toString(); } const std::string getDesc() const { return mCtx.header.desc.toString(); } const MasterList &getMasters() const { return mMasters; } @@ -261,7 +260,6 @@ private: ESM_Context mCtx; // Special file signifier (see SpecialFile enum above) - int mSpf; // Buffer for ESM strings std::vector mBuffer; From b085c4f7492dcfad922e4ed8260142d0bef64d67 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Mar 2013 16:53:42 +0100 Subject: [PATCH 0671/1483] removing more leftovers --- components/esm/esmcommon.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index af83ad816a..a8dfcf0bf7 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -14,13 +14,6 @@ enum Version VER_13 = 0x3fa66666 }; -enum FileType - { - FT_ESP = 0, // Plugin - FT_ESM = 1, // Master - FT_ESS = 32 // Savegame - }; - /* A structure used for holding fixed-length strings. In the case of LEN=4, it can be more efficient to match the string as a 32 bit number, therefore the struct is implemented as a union with an int. From bcdab2aeab59f37281daa49f08d09c25f548b765 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 11 Mar 2013 19:32:39 +0100 Subject: [PATCH 0672/1483] Fix wrong padding breaking local map for cells where the bounds center is far from the origin --- apps/openmw/mwrender/localmap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 3efcd08dde..c86a61cfae 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -162,7 +162,8 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mBounds.merge(Vector3(c4.x, c4.y, 0)); // apply a little padding - mBounds.scale ((mBounds.getSize ()+Ogre::Vector3(1000,1000,0)) / mBounds.getSize ()); + mBounds.setMinimum (mBounds.getMinimum() - Vector3(500,500,0)); + mBounds.setMaximum (mBounds.getMaximum() + Vector3(500,500,0)); Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); From 75f86f3a855b52432a0d4811674311c50fb4cab4 Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 12 Mar 2013 01:03:15 +0100 Subject: [PATCH 0673/1483] Some changes to the stylesheet and other small GUI improvements --- files/ui/mainwindow.ui | 2 +- files/ui/playpage.ui | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/files/ui/mainwindow.ui b/files/ui/mainwindow.ui index 8143fa24df..a1dfb172b2 100644 --- a/files/ui/mainwindow.ui +++ b/files/ui/mainwindow.ui @@ -5,7 +5,7 @@ 575 - 525 + 535 diff --git a/files/ui/playpage.ui b/files/ui/playpage.ui index 6b8b66b208..c0320de1eb 100644 --- a/files/ui/playpage.ui +++ b/files/ui/playpage.ui @@ -19,6 +19,9 @@ QFrame::Plain + + 0 + 30 @@ -40,10 +43,14 @@ border-color: rgba(0, 0, 0, 125); border-style: solid; border-radius: 2px; + + font-size: 12pt; + font-family: "EB Garamond", "EB Garamond 08"; + color: black; } /*QComboBox gets the "on" state when the popup is open */ -#profilesComboBox:!editable:on, #ProfilesComboBox::drop-down:editable:on { +#profilesComboBox:!editable:on { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(0, 0, 0, 75), stop:0.1 rgba(0, 0, 0, 15), @@ -52,13 +59,9 @@ border: 1px solid rgba(0, 0, 0, 55); } -#profilesComboBox { /* shift the text when the popup opens */ +#profilesComboBox:on { /* shift the text when the popup opens */ padding-top: 3px; padding-left: 4px; - - font-size: 12pt; - font-family: "EB Garamond", "EB Garamond 08"; - color: black; } #profilesComboBox::drop-down { @@ -82,7 +85,6 @@ left: 1px; } - #profilesComboBox QAbstractItemView { border: 0px; }
From 81604613b5b1c97f9862f1c9efa4925db69dd114 Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 12 Mar 2013 01:29:13 +0100 Subject: [PATCH 0674/1483] Narrowed down includes to improve compile time --- apps/launcher/datafilespage.cpp | 7 +++++-- apps/launcher/graphicspage.cpp | 4 +++- apps/launcher/maindialog.cpp | 9 ++++++++- apps/launcher/playpage.cpp | 6 +++++- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 444d05b2a0..512c4b2f82 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -1,6 +1,9 @@ #include "datafilespage.hpp" -#include +#include +#include +#include +#include #include @@ -97,7 +100,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam connect(mastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); - + connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); connect(splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 3caae2c36d..8d09cf3c03 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,6 +1,8 @@ #include "graphicspage.hpp" -#include +#include +#include +#include #include diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 5d11421d0f..c478d17fd1 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,6 +1,13 @@ #include "maindialog.hpp" -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "utils/checkablemessagebox.hpp" diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index d6d25d71d0..46900c5958 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -1,6 +1,10 @@ #include "playpage.hpp" -#include +#include + +#ifdef Q_OS_MAC +#include +#endif PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { From 543f57373919ac50140810bdf840f698dbb03b1c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Mar 2013 02:02:59 +0100 Subject: [PATCH 0675/1483] Fix the firstguard armor mod --- apps/openmw/mwworld/actionequip.cpp | 38 ++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 2d257aa614..797085267f 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -47,9 +47,9 @@ namespace MWWorld // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) if(npcRace == "argonian" || npcRace == "khajiit") { - if(*slot == MWWorld::InventoryStore::Slot_Helmet){ + if(*slot == MWWorld::InventoryStore::Slot_Helmet) + { std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) parts = it->get()->mBase->mParts.mParts; else @@ -74,19 +74,35 @@ namespace MWWorld if (*slot == MWWorld::InventoryStore::Slot_Boots) { - // Only notify the player, not npcs - if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + bool allow = true; + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { - if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}", std::vector()); - } - - else // It's boots + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}", std::vector()); + allow = false; + // Only notify the player, not npcs + if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}", std::vector()); + } + + else // It's boots + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}", std::vector()); + } + } + break; } } - break; + + if(!allow) + break; } } From eeb60edb65bf0870284e9702f16c90247b020c36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Mar 2013 02:09:54 +0100 Subject: [PATCH 0676/1483] Properly check for the Beast flag instead of hardcoding beast races --- apps/openmw/mwworld/actionequip.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 797085267f..eb2ae9dca7 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -45,7 +45,8 @@ namespace MWWorld { // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) - if(npcRace == "argonian" || npcRace == "khajiit") + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) { if(*slot == MWWorld::InventoryStore::Slot_Helmet) { From 46d8f3ce5a80ff98db466b6a73713b5ded503120 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Mar 2013 02:44:03 +0100 Subject: [PATCH 0677/1483] Fix hardcoded race IDs --- apps/openmw/mwworld/worldimp.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1d1ece78a6..7b7560082c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -940,19 +940,16 @@ namespace MWWorld if (Misc::StringUtils::ciEqual(record.mId, "player")) { - static const char *sRaces[] = - { - "Argonian", "Breton", "Dark Elf", "High Elf", "Imperial", "Khajiit", "Nord", "Orc", "Redguard", - "Woodelf", 0 - }; + std::vector ids; + getStore().get().listIdentifier(ids); - int i=0; + unsigned int i=0; - for (; sRaces[i]; ++i) - if (Misc::StringUtils::ciEqual (sRaces[i], record.mRace)) + for (; isetInt ("pcrace", sRaces[i] ? i+1 : 0); + mGlobalVariables->setInt ("pcrace", (i == ids.size()) ? 0 : i+1); const ESM::NPC *player = mPlayer->getPlayer().get()->mBase; From 41a958cd4ef8a68d82823caac8717dc943c91ae3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Mar 2013 02:50:23 +0100 Subject: [PATCH 0678/1483] Fix hardcoded beast races in MWClass::Npc::getModel --- apps/openmw/mwclass/npc.cpp | 9 +++------ apps/openmw/mwworld/worldimp.cpp | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f074d03684..d4e5e5cd67 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -183,13 +183,10 @@ namespace MWClass std::string bodyRaceID = headID.substr(0, end); std::string model = "meshes\\base_anim.nif"; - if (bodyRaceID == "b_n_khajiit_m_" || - bodyRaceID == "b_n_khajiit_f_" || - bodyRaceID == "b_n_argonian_m_" || - bodyRaceID == "b_n_argonian_f_") - { + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); + if(race->mData.mFlags & ESM::Race::Beast) model = "meshes\\base_animkna.nif"; - } + return model; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7b7560082c..a933713dd7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -233,8 +233,6 @@ namespace MWWorld mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); mRendering->attachCameraTo(mPlayer->getPlayer()); - mPhysics->addActor(mPlayer->getPlayer()); - // global variables mGlobalVariables = new Globals (mStore); @@ -1315,6 +1313,7 @@ namespace MWWorld void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); + mPhysics->addActor(mPlayer->getPlayer()); } void World::setupExternalRendering (MWRender::ExternalRendering& rendering) From f574c37e93d42faa6e820894990075dea79b32eb Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 12 Mar 2013 04:00:43 +0100 Subject: [PATCH 0679/1483] Added encoding flag to ini importer arguments --- apps/launcher/maindialog.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c478d17fd1..e435bd391c 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include "utils/checkablemessagebox.hpp" #include "playpage.hpp" @@ -210,10 +212,15 @@ bool MainDialog::showFirstRunDialog() // Construct the arguments to run the importer QStringList arguments; - if (msgBox.isChecked()) - arguments.append(QString("-g")); + if (msgBox.isChecked()) + arguments.append(QString("--game-files")); + + arguments.append(QString("--encoding")); + arguments.append(mGameSettings.value(QString("encoding"), QString("win1252"))); + arguments.append(QString("--ini")); arguments.append(iniPaths.first()); + arguments.append(QString("--cfg")); arguments.append(path); if (!startProgram(QString("mwiniimport"), arguments, false)) @@ -666,7 +673,7 @@ bool MainDialog::startProgram(const QString &name, const QStringList &arguments, return false; } - if (process.exitCode() != 0) { + if (process.exitCode() != 0 || process.exitStatus() == QProcess::CrashExit) { QString error(process.readAllStandardError()); error.append(tr("\nArguments:\n")); error.append(arguments.join(" ")); From b2d522aa4d0678017d6cff46f06790196e529783 Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 12 Mar 2013 04:01:05 +0100 Subject: [PATCH 0680/1483] Added support for non-latin characters in esx metadata --- .../fileorderlist/model/datafilesmodel.cpp | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index b33e2e12ab..3165341246 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -157,7 +159,7 @@ Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const if (!file) return Qt::NoItemFlags; - if (canBeChecked(file)) { + if (canBeChecked(file)) { if (index.column() == 0) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } else { @@ -226,7 +228,7 @@ bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2) return true; if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) return false; - + return e1->fileName().toLower() < e2->fileName().toLower(); } @@ -237,10 +239,6 @@ bool lessThanDate(const EsmFile *e1, const EsmFile *e2) } else { return false; } -// if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) -// return false; - -// return e1->fileName().toLower() < e2->fileName().toLower(); } void DataFilesModel::sort(int column, Qt::SortOrder order) @@ -270,17 +268,32 @@ void DataFilesModel::addFiles(const QString &path) filters << "*.esp" << "*.esm"; dir.setNameFilters(filters); + // Create a decoder for non-latin characters in esx metadata + QTextCodec *codec; + + if (mEncoding == QLatin1String("win1252")) { + codec = QTextCodec::codecForName("windows-1252"); + } else if (mEncoding == QLatin1String("win1251")) { + codec = QTextCodec::codecForName("windows-1251"); + } else if (mEncoding == QLatin1String("win1250")) { + codec = QTextCodec::codecForName("windows-1250"); + } else { + return; // This should never happen; + } + + QTextDecoder *decoder = codec->makeDecoder(); + foreach (const QString &path, dir.entryList()) { QFileInfo info(dir.absoluteFilePath(path)); EsmFile *file = new EsmFile(path); - try { ESM::ESMReader fileReader; - ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString())); + ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding.toStdString())); fileReader.setEncoder(&encoder); fileReader.open(dir.absoluteFilePath(path).toStdString()); + ESM::ESMReader::MasterList mlist = fileReader.getMasters(); QStringList masters; @@ -289,13 +302,13 @@ void DataFilesModel::addFiles(const QString &path) masters.append(master); } - file->setAuthor(QString::fromStdString(fileReader.getAuthor())); + file->setAuthor(decoder->toUnicode(fileReader.getAuthor().c_str())); file->setSize(info.size()); file->setDates(info.lastModified(), info.lastRead()); file->setVersion(fileReader.getFVer()); file->setPath(info.absoluteFilePath()); file->setMasters(masters); - file->setDescription(QString::fromStdString(fileReader.getDesc())); + file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str())); // Put the file in the table @@ -308,6 +321,8 @@ void DataFilesModel::addFiles(const QString &path) } } + + delete decoder; } QModelIndex DataFilesModel::indexFromItem(EsmFile *item) const @@ -369,10 +384,10 @@ QStringList DataFilesModel::checkedItems() QStringList DataFilesModel::checkedItemsPaths() { QStringList list; - + QList::ConstIterator it; QList::ConstIterator itEnd = mFiles.constEnd(); - + int i = 0; for (it = mFiles.constBegin(); it != itEnd; ++it) { EsmFile *file = item(i); @@ -381,7 +396,7 @@ QStringList DataFilesModel::checkedItemsPaths() if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file)) list << file->path(); } - + return list; } From 31ba332647e74e1955909d1dd57a7b7c8409de17 Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 12 Mar 2013 04:05:14 +0100 Subject: [PATCH 0681/1483] Moved Windows icon to files/launcher --- apps/launcher/CMakeLists.txt | 10 +++++----- {apps => files}/launcher/launcher.rc | 0 2 files changed, 5 insertions(+), 5 deletions(-) rename {apps => files}/launcher/launcher.rc (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index a63898c0ec..eb93d71e78 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -12,7 +12,7 @@ set(LAUNCHER utils/checkablemessagebox.cpp utils/textinputdialog.cpp - launcher.rc + ${CMAKE_SOURCE_DIR}/files/launcher/launcher.rc ) set(LAUNCHER_HEADER @@ -43,10 +43,10 @@ set(LAUNCHER_HEADER_MOC ) set(LAUNCHER_UI - ../../files/ui/datafilespage.ui - ../../files/ui/graphicspage.ui - ../../files/ui/mainwindow.ui - ../../files/ui/playpage.ui + ${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui + ${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui + ${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui + ${CMAKE_SOURCE_DIR}/files/ui/playpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) diff --git a/apps/launcher/launcher.rc b/files/launcher/launcher.rc similarity index 100% rename from apps/launcher/launcher.rc rename to files/launcher/launcher.rc From 9e68a420ae5dc10e6e12ecf40ce8c99c600e33d5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 08:15:20 +0100 Subject: [PATCH 0682/1483] restructuring tes3 record structs --- apps/esmtool/esmtool.cpp | 6 +-- apps/openmw/mwworld/esmstore.cpp | 5 +- components/esm/esmcommon.hpp | 52 ++++++++++++------- components/esm/esmreader.cpp | 7 +-- components/esm/esmreader.hpp | 21 +++----- components/esm/esmwriter.cpp | 20 +++---- components/esm/esmwriter.hpp | 3 +- components/esm/loadcell.cpp | 4 +- .../fileorderlist/model/datafilesmodel.cpp | 12 ++--- 9 files changed, 69 insertions(+), 61 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 8d060cbd22..5cc1b6bcbb 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -23,7 +23,7 @@ struct ESMData std::string author; std::string description; int version; - ESM::ESMReader::MasterList masters; + std::vector masters; std::deque mRecords; std::map > mCellRefs; @@ -289,7 +289,7 @@ int load(Arguments& info) std::cout << "Author: " << esm.getAuthor() << std::endl << "Description: " << esm.getDesc() << std::endl << "File format version: " << esm.getFVer() << std::endl; - ESM::ESMReader::MasterList m = esm.getMasters(); + std::vector m = esm.getMasters(); if (!m.empty()) { std::cout << "Masters:" << std::endl; @@ -427,7 +427,7 @@ int clone(Arguments& info) esm.setDescription(info.data.description); esm.setVersion(info.data.version); - for (ESM::ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) + for (std::vector::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) esm.addMaster(it->name, it->size); std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 257676076c..09a39ff8b1 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -27,14 +27,15 @@ void ESMStore::load(ESM::ESMReader &esm) ESM::Dialogue *dialogue = 0; + /// \todo Move this to somewhere else. ESMReader? // Cache parent esX files by tracking their indices in the global list of // all files/readers used by the engine. This will greaty accelerate // refnumber mangling, as required for handling moved references. int index = ~0; - const ESM::ESMReader::MasterList &masters = esm.getMasters(); + const std::vector &masters = esm.getMasters(); std::vector *allPlugins = esm.getGlobalReaderList(); for (size_t j = 0; j < masters.size(); j++) { - ESM::MasterData &mast = const_cast(masters[j]); + ESM::Header::MasterData &mast = const_cast(masters[j]); std::string fname = mast.name; for (int i = 0; i < esm.getIndex(); i++) { const std::string &candidate = allPlugins->at(i).getContext().filename; diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index a8dfcf0bf7..cbdd05a49a 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -2,6 +2,8 @@ #define OPENMW_ESM_COMMON_H #include +#include +#include #include #include @@ -43,6 +45,8 @@ union NAME_T bool operator!=(int v) const { return v != val; } std::string toString() const { return std::string(name, strnlen(name, LEN)); } + + void assign (const std::string& value) { std::strncpy (name, value.c_str(), LEN); } }; typedef NAME_T<4> NAME; @@ -53,27 +57,37 @@ typedef NAME_T<256> NAME256; #pragma pack(push) #pragma pack(1) /// File header data for all ES files -struct HEDRstruct +struct Header { - /* File format version. This is actually a float, the supported - versions are 1.2 and 1.3. These correspond to: - 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 - */ - int version; - int type; // 0=esp, 1=esm, 32=ess (unused) - NAME32 author; // Author's name - NAME256 desc; // File description - int records; // Number of records? Not used. -}; + struct Data + { + /* File format version. This is actually a float, the supported + versions are 1.2 and 1.3. These correspond to: + 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 + */ + int version; + int type; // 0=esp, 1=esm, 32=ess (unused) + NAME32 author; // Author's name + NAME256 desc; // File description + int records; // Number of records? Not used. + }; -// Defines another files (esm or esp) that this file depends upon. -struct MasterData -{ - std::string name; - uint64_t size; - int index; // Position of the parent file in the global list of loaded files -}; + // Defines another files (esm or esp) that this file depends upon. + struct MasterData + { + std::string name; + uint64_t size; + int index; // Position of the parent file in the global list of loaded files + }; + Data mData; + std::vector mMaster; +}; +#pragma pack(pop) + + +#pragma pack(push) +#pragma pack(1) // Data that is only present in save game files struct SaveData { @@ -95,7 +109,7 @@ struct ESM_Context uint32_t leftRec, leftSub; size_t leftFile; NAME recName, subName; - HEDRstruct header; + Header::Data header; // When working with multiple esX files, we will generate lists of all files that // actually contribute to a specific cell. Therefore, we need to store the index // of the file belonging to this contest. See CellStore::(list/load)refs for details. diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 98c598eb9a..70ab0caa38 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -63,16 +63,17 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) getRecHeader(); // Get the header - getHNT(mCtx.header, "HEDR", 300); + getHNT (mHeader.mData, "HEDR", 300); + mCtx.header = mHeader.mData; // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. while (isNextSub("MAST")) { - MasterData m; + Header::MasterData m; m.name = getHString(); m.size = getHNLong("DATA"); - mMasters.push_back(m); + mHeader.mMaster.push_back(m); } } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index dd7809fb3c..6850c7a148 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -22,25 +22,17 @@ public: ESMReader(void); - /************************************************************************* - * - * Public type definitions - * - *************************************************************************/ - - typedef std::vector MasterList; - /************************************************************************* * * Information retrieval * *************************************************************************/ - int getVer() const { return mCtx.header.version; } - float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } - const std::string getAuthor() const { return mCtx.header.author.toString(); } - const std::string getDesc() const { return mCtx.header.desc.toString(); } - const MasterList &getMasters() const { return mMasters; } + int getVer() const { return mHeader.mData.version; } + float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; } + const std::string getAuthor() const { return mHeader.mData.author.toString(); } + const std::string getDesc() const { return mHeader.mData.desc.toString(); } + const std::vector &getMasters() const { return mHeader.mMaster; } const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } @@ -264,7 +256,8 @@ private: // Buffer for ESM strings std::vector mBuffer; - MasterList mMasters; + Header mHeader; + std::vector *mGlobalReaderList; ToUTF8::Utf8Encoder* mEncoder; }; diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index faceeeaa6f..6a3bfa9bdf 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -1,6 +1,5 @@ #include "esmwriter.hpp" #include -#include bool count = true; @@ -9,30 +8,30 @@ namespace ESM int ESMWriter::getVersion() { - return m_header.version; + return mHeader.mData.version; } void ESMWriter::setVersion(int ver) { - m_header.version = ver; + mHeader.mData.version = ver; } void ESMWriter::setAuthor(const std::string& auth) { - strncpy((char*)&m_header.author, auth.c_str(), 32); + mHeader.mData.author.assign (auth); } void ESMWriter::setDescription(const std::string& desc) { - strncpy((char*)&m_header.desc, desc.c_str(), 256); + mHeader.mData.desc.assign (desc); } void ESMWriter::addMaster(const std::string& name, uint64_t size) { - MasterData d; + Header::MasterData d; d.name = name; d.size = size; - m_masters.push_back(d); + mHeader.mMaster.push_back(d); } void ESMWriter::save(const std::string& file) @@ -48,11 +47,12 @@ void ESMWriter::save(std::ostream& file) startRecord("TES3", 0); - m_header.records = 0; - writeHNT("HEDR", m_header, 300); + mHeader.mData.records = 0; + writeHNT("HEDR", mHeader.mData, 300); m_headerPos = m_stream->tellp() - (std::streampos)4; - for (std::list::iterator it = m_masters.begin(); it != m_masters.end(); ++it) + for (std::vector::iterator it = mHeader.mMaster.begin(); + it != mHeader.mMaster.end(); ++it) { writeHNCString("MAST", it->name); writeHNT("DATA", it->size); diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index f488cce3e1..e8ff27577a 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -88,14 +88,13 @@ public: void write(const char* data, size_t size); private: - std::list m_masters; std::list m_records; std::ostream* m_stream; std::streampos m_headerPos; ToUTF8::Utf8Encoder* m_encoder; int m_recordCount; - HEDRstruct m_header; + Header mHeader; }; } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 76a48e5ec4..da60f76af8 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -245,7 +245,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // If the most significant 8 bits are used, then this reference already exists. // In this case, do not spawn a new reference, but overwrite the old one. ref.mRefnum &= 0x00ffffff; // delete old plugin ID - const ESM::ESMReader::MasterList &masters = esm.getMasters(); + const std::vector &masters = esm.getMasters(); global = masters[local-1].index + 1; ref.mRefnum |= global << 24; // insert global plugin ID } @@ -348,7 +348,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) int local = (mref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; mref.mRefnum &= 0x00ffffff; // delete old plugin ID - const ESM::ESMReader::MasterList &masters = esm.getMasters(); + const std::vector &masters = esm.getMasters(); global = masters[local-1].index + 1; mref.mRefnum |= global << 24; // insert global plugin ID diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index b33e2e12ab..71a320190c 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -157,7 +157,7 @@ Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const if (!file) return Qt::NoItemFlags; - if (canBeChecked(file)) { + if (canBeChecked(file)) { if (index.column() == 0) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } else { @@ -226,7 +226,7 @@ bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2) return true; if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) return false; - + return e1->fileName().toLower() < e2->fileName().toLower(); } @@ -281,7 +281,7 @@ void DataFilesModel::addFiles(const QString &path) fileReader.setEncoder(&encoder); fileReader.open(dir.absoluteFilePath(path).toStdString()); - ESM::ESMReader::MasterList mlist = fileReader.getMasters(); + std::vector mlist = fileReader.getMasters(); QStringList masters; for (unsigned int i = 0; i < mlist.size(); ++i) { @@ -369,10 +369,10 @@ QStringList DataFilesModel::checkedItems() QStringList DataFilesModel::checkedItemsPaths() { QStringList list; - + QList::ConstIterator it; QList::ConstIterator itEnd = mFiles.constEnd(); - + int i = 0; for (it = mFiles.constBegin(); it != itEnd; ++it) { EsmFile *file = item(i); @@ -381,7 +381,7 @@ QStringList DataFilesModel::checkedItemsPaths() if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file)) list << file->path(); } - + return list; } From 731ac6a16084e86fef90bff7ca8a676eb652a279 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 08:30:51 +0100 Subject: [PATCH 0683/1483] removed redundant copy of Header::Data --- components/esm/esmcommon.hpp | 1 - components/esm/esmreader.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index cbdd05a49a..42fdc1211b 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -109,7 +109,6 @@ struct ESM_Context uint32_t leftRec, leftSub; size_t leftFile; NAME recName, subName; - Header::Data header; // When working with multiple esX files, we will generate lists of all files that // actually contribute to a specific cell. Therefore, we need to store the index // of the file belonging to this contest. See CellStore::(list/load)refs for details. diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 70ab0caa38..ea2bf76945 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -64,7 +64,6 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) // Get the header getHNT (mHeader.mData, "HEDR", 300); - mCtx.header = mHeader.mData; // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. From 16570ce87b021596e24b281b4e12c66f455e7896 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 09:16:03 +0100 Subject: [PATCH 0684/1483] moved header record struct to separate file --- components/CMakeLists.txt | 2 +- components/esm/esmcommon.hpp | 33 ----------------------- components/esm/esmreader.cpp | 13 +-------- components/esm/esmreader.hpp | 4 ++- components/esm/esmwriter.cpp | 18 +++---------- components/esm/esmwriter.hpp | 7 ++--- components/esm/loadtes3.cpp | 40 +++++++++++++++++++++++++++ components/esm/loadtes3.hpp | 52 ++++++++++++++++++++++++++++++++++++ 8 files changed, 105 insertions(+), 64 deletions(-) create mode 100644 components/esm/loadtes3.cpp create mode 100644 components/esm/loadtes3.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 38625fb529..f7b97056cb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (esm loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat - loadweap records aipackage effectlist spelllist variant variantimp + loadweap records aipackage effectlist spelllist variant variantimp loadtes3 ) add_component_dir (misc diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 42fdc1211b..6f51c767ec 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -2,7 +2,6 @@ #define OPENMW_ESM_COMMON_H #include -#include #include #include @@ -54,38 +53,6 @@ typedef NAME_T<32> NAME32; typedef NAME_T<64> NAME64; typedef NAME_T<256> NAME256; -#pragma pack(push) -#pragma pack(1) -/// File header data for all ES files -struct Header -{ - struct Data - { - /* File format version. This is actually a float, the supported - versions are 1.2 and 1.3. These correspond to: - 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 - */ - int version; - int type; // 0=esp, 1=esm, 32=ess (unused) - NAME32 author; // Author's name - NAME256 desc; // File description - int records; // Number of records? Not used. - }; - - // Defines another files (esm or esp) that this file depends upon. - struct MasterData - { - std::string name; - uint64_t size; - int index; // Position of the parent file in the global list of loaded files - }; - - Data mData; - std::vector mMaster; -}; -#pragma pack(pop) - - #pragma pack(push) #pragma pack(1) // Data that is only present in save game files diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index ea2bf76945..979088b801 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -62,18 +62,7 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) getRecHeader(); - // Get the header - getHNT (mHeader.mData, "HEDR", 300); - - // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. - - while (isNextSub("MAST")) - { - Header::MasterData m; - m.name = getHString(); - m.size = getHNLong("DATA"); - mHeader.mMaster.push_back(m); - } + mHeader.load (*this); } void ESMReader::open(const std::string &file) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 6850c7a148..e377470eeb 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -12,7 +12,9 @@ #include #include + #include "esmcommon.hpp" +#include "loadtes3.hpp" namespace ESM { @@ -20,7 +22,7 @@ class ESMReader { public: - ESMReader(void); + ESMReader(); /************************************************************************* * diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index 6a3bfa9bdf..edb681f329 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -1,5 +1,8 @@ #include "esmwriter.hpp" + +#include #include +#include bool count = true; @@ -47,26 +50,13 @@ void ESMWriter::save(std::ostream& file) startRecord("TES3", 0); - mHeader.mData.records = 0; - writeHNT("HEDR", mHeader.mData, 300); - m_headerPos = m_stream->tellp() - (std::streampos)4; - - for (std::vector::iterator it = mHeader.mMaster.begin(); - it != mHeader.mMaster.end(); ++it) - { - writeHNCString("MAST", it->name); - writeHNT("DATA", it->size); - } + mHeader.save (*this); endRecord("TES3"); } void ESMWriter::close() { - std::cout << "Writing amount of saved records (" << m_recordCount - 1 << ")" << std::endl; - m_stream->seekp(m_headerPos); - writeT(m_recordCount-1); - m_stream->seekp(0, std::ios::end); m_stream->flush(); if (!m_records.empty()) diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index e8ff27577a..b0e9329d4b 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -1,12 +1,13 @@ #ifndef OPENMW_ESM_WRITER_H #define OPENMW_ESM_WRITER_H -#include +#include #include -#include + +#include #include "esmcommon.hpp" -#include +#include "loadtes3.hpp" namespace ESM { diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp new file mode 100644 index 0000000000..64f1446f18 --- /dev/null +++ b/components/esm/loadtes3.cpp @@ -0,0 +1,40 @@ + +#include "loadtes3.hpp" + +#include "esmcommon.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::Header::blank() +{ + mData.version = ESM::VER_13; + mData.type = 0; + mData.author.assign (""); + mData.desc.assign (""); + mData.records = 0; +} + +void ESM::Header::load (ESMReader &esm) +{ + esm.getHNT (mData, "HEDR", 300); + + while (esm.isNextSub ("MAST")) + { + MasterData m; + m.name = esm.getHString(); + m.size = esm.getHNLong ("DATA"); + mMaster.push_back (m); + } +} + +void ESM::Header::save (ESMWriter &esm) +{ + esm.writeHNT ("HEDR", mData, 300); + + for (std::vector::iterator iter = mMaster.begin(); + iter != mMaster.end(); ++iter) + { + esm.writeHNCString ("MAST", iter->name); + esm.writeHNT ("DATA", iter->size); + } +} \ No newline at end of file diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp new file mode 100644 index 0000000000..c0b1e3af77 --- /dev/null +++ b/components/esm/loadtes3.hpp @@ -0,0 +1,52 @@ +#ifndef COMPONENT_ESM_TES3_H +#define COMPONENT_ESM_TES3_H + +#include + +#include "esmcommon.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + +#pragma pack(push) +#pragma pack(1) + + /// \brief File header record + struct Header + { + struct Data + { + /* File format version. This is actually a float, the supported + versions are 1.2 and 1.3. These correspond to: + 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 + */ + int version; + int type; // 0=esp, 1=esm, 32=ess (unused) + NAME32 author; // Author's name + NAME256 desc; // File description + int records; // Number of records? Not used. + }; + + // Defines another files (esm or esp) that this file depends upon. + struct MasterData + { + std::string name; + uint64_t size; + int index; // Position of the parent file in the global list of loaded files + }; + + Data mData; + std::vector mMaster; + + void blank(); + + void load (ESMReader &esm); + void save (ESMWriter &esm); + }; +#pragma pack(pop) + +} + +#endif \ No newline at end of file From 50abb221625625ae6b448b65ccf74626f3f61437 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Tue, 12 Mar 2013 06:28:13 -0500 Subject: [PATCH 0685/1483] Fix to allow application closing from multiple views and a single view. --- apps/opencs/model/doc/document.cpp | 7 +- apps/opencs/model/doc/document.hpp | 3 +- apps/opencs/view/doc/view.cpp | 10 ++- apps/opencs/view/doc/view.hpp | 6 +- apps/opencs/view/doc/viewmanager.cpp | 89 ++++++++++--------- apps/opencs/view/doc/viewmanager.hpp | 11 ++- .../fileorderlist/model/datafilesmodel.cpp | 2 +- 7 files changed, 76 insertions(+), 52 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 3d8f961121..af34aeedf4 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,7 +2,7 @@ #include "document.hpp" #include - +#include void CSMDoc::Document::load (const std::vector::const_iterator& begin, const std::vector::const_iterator& end, bool lastAsModified) { @@ -237,6 +237,11 @@ CSMDoc::Document::Document (const std::vector& files, b connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); } +CSMDoc::Document::~Document() +{ + qDebug() << "document destroyed"; +} + QUndoStack& CSMDoc::Document::getUndoStack() { return mUndoStack; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index a7b198689e..94d5fe85cc 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -63,6 +63,7 @@ namespace CSMDoc public: Document (const std::vector& files, bool new_); + ~Document(); QUndoStack& getUndoStack(); @@ -105,4 +106,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index dfbd92a609..995d3ca2e2 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -46,7 +46,8 @@ void CSVDoc::View::setupFileMenu() file->addAction(close); QAction *exit = new QAction (tr ("&Exit"), this); - connect (exit, SIGNAL (triggered()), QApplication::instance(), SLOT (closeAllWindows())); + connect (exit, SIGNAL (triggered()), this, SLOT (exit())); + connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *))); file->addAction(exit); } @@ -131,8 +132,6 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - // setDockOptions (QMainWindow::AllowNestedDocks); - resize (300, 300); /// \todo get default size from settings and set reasonable minimal size mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); @@ -255,3 +254,8 @@ CSVDoc::Operations *CSVDoc::View::getOperations() const { return mOperations; } + +void CSVDoc::View::exit() +{ + emit exitApplicationRequest (this); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 92c57fe9ec..e91a4d4a80 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -66,6 +66,8 @@ namespace CSVDoc void updateActions(); + void exitApplication(); + public: View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); @@ -92,7 +94,7 @@ namespace CSVDoc void loadDocumentRequest(); - void closeAllViews (View *); + void exitApplicationRequest (CSVDoc::View *view); public slots: @@ -106,6 +108,8 @@ namespace CSVDoc void save(); + void exit(); + void verify(); void addGlobalsSubView(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 83ace49387..527e3b2044 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -36,7 +36,7 @@ void CSVDoc::ViewManager::updateIndices() } CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) - : mDocumentManager (documentManager), mCloseMeOnSaveStateChange(0), mUserWarned(false) + : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; @@ -45,16 +45,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); - - connect (this, SIGNAL (exitApplication()), QApplication::instance(), SLOT (closeAllWindows())); - } CSVDoc::ViewManager::~ViewManager() { delete mDelegateFactories; - //not needed due to deletion in ViewManager::closeRequest? for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; } @@ -112,32 +108,40 @@ bool CSVDoc::ViewManager::closeRequest (View *view) CSMDoc::Document *document = view->getDocument(); - //notify user of saving in progress - if ( (document->getState() & CSMDoc::State_Saving) ) - continueWithClose = showSaveInProgressMessageBox (iter); - - //notify user of unsaved changes and process response - else if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (iter); - - if (continueWithClose) + if (last) + continueWithClose = notifySaveOnClose (view); + else { (*iter)->deleteLater(); mViews.erase (iter); - if (last) - mDocumentManager.removeDocument (document); - else - updateIndices(); + updateIndices(); } } return continueWithClose; } -bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::iterator viewIter) +bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view) +{ + bool result = true; + CSMDoc::Document *document = view->getDocument(); + + //notify user of saving in progress + if ( (document->getState() & CSMDoc::State_Saving) ) + result = showSaveInProgressMessageBox (view); + + //notify user of unsaved changes and process response + else if ( document->getState() & CSMDoc::State_Modified) + result = showModifiedDocumentMessageBox (view); + + return result; +} + +bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) { QMessageBox messageBox; + CSMDoc::Document *document = view->getDocument(); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); @@ -147,31 +151,31 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::i bool retVal = true; connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); - connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + + connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + mUserWarned = true; - int response = messageBox.exec(); - mUserWarned = false; switch (response) { case QMessageBox::Save: - (*viewIter)->getDocument()->save(); - mCloseMeOnSaveStateChange = viewIter; + document->save(); + mExitOnSaveStateChange = true; retVal = false; break; case QMessageBox::Discard: - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); break; case QMessageBox::Cancel: //disconnect to prevent unintended view closures - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); retVal = false; break; @@ -183,9 +187,10 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::i return retVal; } -bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::iterator viewIter) +bool CSVDoc::ViewManager::showSaveInProgressMessageBox (CSVDoc::View *view) { QMessageBox messageBox; + CSMDoc::Document *document = view->getDocument(); messageBox.setText ("The document is currently being saved."); messageBox.setInformativeText("Do you want to close now and abort saving, or wait until saving has completed?"); @@ -199,38 +204,37 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::ite bool retVal = true; //Connections shut down message box if operation ends before user makes a decision. - connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); //set / clear the user warned flag to indicate whether or not the message box is currently active. mUserWarned = true; - messageBox.exec(); - mUserWarned = false; //if closed by the warning handler, defaults to the RejectRole button (closeButton) if (messageBox.clickedButton() == waitButton) { //save the View iterator for shutdown after the save operation ends - mCloseMeOnSaveStateChange = viewIter; + mExitOnSaveStateChange = true; retVal = false; } else if (messageBox.clickedButton() == closeButton) { //disconnect to avoid segmentation fault - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); - (*viewIter)->abortOperation(CSMDoc::State_Saving); - mCloseMeOnSaveStateChange = mViews.end(); + disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + + view->abortOperation(CSMDoc::State_Saving); + mExitOnSaveStateChange = true; } else if (messageBox.clickedButton() == cancelButton) { //abort shutdown, allow save to complete //disconnection to prevent unintended view closures - mCloseMeOnSaveStateChange = mViews.end(); - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + mExitOnSaveStateChange = false; + disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); retVal = false; } @@ -262,10 +266,13 @@ void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *doc //otherwise, the user has closed the message box before the save operation ended. //exit the application - else if (mCloseMeOnSaveStateChange!=mViews.end()) - { - emit exitApplication(); - mCloseMeOnSaveStateChange = mViews.end(); - } + else if (mExitOnSaveStateChange) + QApplication::instance()->exit(); } } + +void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) +{ + if (notifySaveOnClose (view)) + QApplication::instance()->exit(); +} diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index b77e5f5758..90f23eaa11 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -27,7 +27,7 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; - std::vector::iterator mCloseMeOnSaveStateChange; + bool mExitOnSaveStateChange; bool mUserWarned; // not implemented @@ -35,8 +35,9 @@ namespace CSVDoc ViewManager& operator= (const ViewManager&); void updateIndices(); - bool showModifiedDocumentMessageBox (std::vector::iterator view); - bool showSaveInProgressMessageBox (std::vector::iterator view); + bool notifySaveOnClose (View *view = 0); + bool showModifiedDocumentMessageBox (View *view); + bool showSaveInProgressMessageBox (View *view); public: @@ -60,7 +61,9 @@ namespace CSVDoc void closeMessageBox(); - void exitApplication(); + public slots: + + void exitApplication (CSVDoc::View *view); private slots: diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index b33e2e12ab..25286e2f85 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -1,6 +1,6 @@ -#include #include #include +#include #include From 75bd30844db2ce8a5e3d1e1e9ea9b12f0bc5854a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 14:33:35 +0100 Subject: [PATCH 0686/1483] added optional format sub-record to tes3 record --- apps/esmtool/esmtool.cpp | 1 + components/esm/esmreader.cpp | 7 ++++++- components/esm/esmreader.hpp | 1 + components/esm/esmwriter.cpp | 10 ++++++++++ components/esm/esmwriter.hpp | 2 ++ components/esm/loadtes3.cpp | 13 +++++++++++++ components/esm/loadtes3.hpp | 3 +++ 7 files changed, 36 insertions(+), 1 deletion(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 5cc1b6bcbb..20c01af259 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -426,6 +426,7 @@ int clone(Arguments& info) esm.setAuthor(info.data.author); esm.setDescription(info.data.description); esm.setVersion(info.data.version); + esm.setRecordCount (recordCount); for (std::vector::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) esm.addMaster(it->name, it->size); diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 979088b801..580e576d05 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -15,11 +15,16 @@ ESM_Context ESMReader::getContext() return mCtx; } -ESMReader::ESMReader(void): +ESMReader::ESMReader(): mBuffer(50*1024) { } +int ESMReader::getFormat() const +{ + return mHeader.mFormat; +} + void ESMReader::restoreContext(const ESM_Context &rc) { // Reopen the file if necessary diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index e377470eeb..f805998e43 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -35,6 +35,7 @@ public: const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } const std::vector &getMasters() const { return mHeader.mMaster; } + int getFormat() const; const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index edb681f329..3ea6bd350a 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -29,6 +29,16 @@ void ESMWriter::setDescription(const std::string& desc) mHeader.mData.desc.assign (desc); } +void ESMWriter::setRecordCount (int count) +{ + mHeader.mData.records = count; +} + +void ESMWriter::setFormat (int format) +{ + mHeader.mFormat = format; +} + void ESMWriter::addMaster(const std::string& name, uint64_t size) { Header::MasterData d; diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index b0e9329d4b..be3ae33abe 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -26,6 +26,8 @@ public: void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8? void setAuthor(const std::string& author); void setDescription(const std::string& desc); + void setRecordCount (int count); + void setFormat (int format); void addMaster(const std::string& name, uint64_t size); diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index 64f1446f18..74d578ba7d 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -12,12 +12,22 @@ void ESM::Header::blank() mData.author.assign (""); mData.desc.assign (""); mData.records = 0; + mFormat = CurrentFormat; } void ESM::Header::load (ESMReader &esm) { esm.getHNT (mData, "HEDR", 300); + if (esm.isNextSub ("FORM")) + { + esm.getHT (mFormat); + if (mFormat<0) + esm.fail ("invalid format code"); + } + else + mFormat = 0; + while (esm.isNextSub ("MAST")) { MasterData m; @@ -31,6 +41,9 @@ void ESM::Header::save (ESMWriter &esm) { esm.writeHNT ("HEDR", mData, 300); + if (mFormat>0) + esm.writeHNT ("FORM", mFormat); + for (std::vector::iterator iter = mMaster.begin(); iter != mMaster.end(); ++iter) { diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp index c0b1e3af77..b73a4c31e4 100644 --- a/components/esm/loadtes3.hpp +++ b/components/esm/loadtes3.hpp @@ -16,6 +16,8 @@ namespace ESM /// \brief File header record struct Header { + static const int CurrentFormat = 0; // most recent known format + struct Data { /* File format version. This is actually a float, the supported @@ -38,6 +40,7 @@ namespace ESM }; Data mData; + int mFormat; std::vector mMaster; void blank(); From 10fad47a8129837973e0e3d88cf94f15626c58c0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 14:51:16 +0100 Subject: [PATCH 0687/1483] some cleanup --- apps/opencs/model/doc/document.cpp | 4 +--- apps/opencs/view/doc/viewmanager.cpp | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index af34aeedf4..7a88335c89 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -238,9 +238,7 @@ CSMDoc::Document::Document (const std::vector& files, b } CSMDoc::Document::~Document() -{ - qDebug() << "document destroyed"; -} +{} QUndoStack& CSMDoc::Document::getUndoStack() { diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 527e3b2044..33300f67a7 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -103,11 +103,6 @@ bool CSVDoc::ViewManager::closeRequest (View *view) { bool last = countViews (view->getDocument())<=1; - /// \todo check if save is in progress -> warn user about possible data loss - /// \todo check if document has not been saved -> return false and start close dialogue - - CSMDoc::Document *document = view->getDocument(); - if (last) continueWithClose = notifySaveOnClose (view); else From d6a5915bbd0039acd74a99db5a77f06662114292 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 14:56:11 +0100 Subject: [PATCH 0688/1483] updated version to 0.22.0 --- CMakeLists.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bdd8b21cf..9aabd60551 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 21) +set (OPENMW_VERSION_MINOR 22) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") diff --git a/readme.txt b/readme.txt index 228278a919..f5997cd256 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.21.0 +Version: 0.22.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From 4c588cbab616115b30f368bd7e018a3f984066d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Mar 2013 17:18:47 +0100 Subject: [PATCH 0689/1483] Levelup dialog is now dynamic; added level descriptions --- apps/openmw/mwgui/levelupdialog.cpp | 24 +++++++++++---- apps/openmw/mwgui/levelupdialog.hpp | 3 ++ apps/openmw/mwgui/widgets.cpp | 29 ++++++++++++++++++ apps/openmw/mwgui/widgets.hpp | 13 ++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 1 + files/mygui/openmw_levelup_dialog.layout | 38 +++++++++++++++++++----- 6 files changed, 96 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 45890b89fe..9473f48b4e 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -23,6 +23,8 @@ namespace MWGui getWidget(mOkButton, "OkButton"); getWidget(mClassImage, "ClassImage"); getWidget(mLevelText, "LevelText"); + getWidget(mLevelDescription, "LevelDescription"); + getWidget(mCoinBox, "Coins"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onOkButtonClicked); @@ -80,11 +82,13 @@ namespace MWGui void LevelupDialog::resetCoins () { - int curX = mMainWidget->getWidth()/2 - (16 + 2) * 1.5; + int curX = 0; for (int i=0; i<3; ++i) { MyGUI::ImageBox* image = mCoins[i]; - image->setCoord(MyGUI::IntCoord(curX,250,16,16)); + image->detachFromWidget(); + image->attachToWidget(mCoinBox); + image->setCoord(MyGUI::IntCoord(curX,0,16,16)); curX += 24+2; } } @@ -95,6 +99,9 @@ namespace MWGui for (unsigned int i=0; idetachFromWidget(); + image->attachToWidget(mMainWidget); + int attribute = mSpentAttributes[i]; int xdiff = mAttributeMultipliers[attribute]->getCaption() == "" ? 0 : 30; @@ -113,8 +120,6 @@ namespace MWGui MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); - center(); - mSpentAttributes.clear(); resetCoins(); @@ -128,16 +133,25 @@ namespace MWGui mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds"); - /// \todo replace this with INI-imported texts int level = creatureStats.getLevel ()+1; mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast(level)); + std::string levelupdescription; + if(level>20) + levelupdescription=world->getFallback("Level_Up_Default"); + else + levelupdescription=world->getFallback("Level_Up_Level"+boost::lexical_cast(level)); + + mLevelDescription->setCaption (levelupdescription); + for (int i=0; i<8; ++i) { MyGUI::TextBox* text = mAttributeMultipliers[i]; int mult = pcStats.getLevelupAttributeMultiplier (i); text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast(mult)); } + + center(); } void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index f5b24530d1..3c8b74800b 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -17,6 +17,9 @@ namespace MWGui MyGUI::Button* mOkButton; MyGUI::ImageBox* mClassImage; MyGUI::TextBox* mLevelText; + MyGUI::EditBox* mLevelDescription; + + MyGUI::Widget* mCoinBox; std::vector mAttributes; std::vector mAttributeValues; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 506b906982..b0f7e6293b 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -586,6 +586,30 @@ void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::s } } +MyGUI::IntSize AutoSizedEditBox::getRequestedSize() +{ + return MyGUI::IntSize(getSize().width, getTextSize().height); +} + +void AutoSizedEditBox::setCaption(const MyGUI::UString& _value) +{ + EditBox::setCaption(_value); + + notifySizeChange (this); +} + +void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) +{ + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + EditBox::setPropertyOverride (_key, _value); + } +} + MyGUI::IntSize AutoSizedButton::getRequestedSize() { @@ -660,6 +684,8 @@ void HBox::align () { sizes.push_back (std::make_pair(w->getSize(), hstretch)); total_width += w->getSize().width; + if (!(w->getUserString("VStretch") == "true")) + total_height = std::max(total_height, w->getSize().height); } if (i != count-1) @@ -783,6 +809,9 @@ void VBox::align () { sizes.push_back (std::make_pair(w->getSize(), vstretch)); total_height += w->getSize().height; + + if (!(w->getUserString("HStretch") == "true")) + total_width = std::max(total_width, w->getSize().width); } if (i != count-1) diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 597bcbe324..d2bcb69257 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace MyGUI { @@ -340,6 +341,18 @@ namespace MWGui virtual void setPropertyOverride(const std::string& _key, const std::string& _value); }; + class AutoSizedEditBox : public AutoSizedWidget, public MyGUI::EditBox + { + MYGUI_RTTI_DERIVED( AutoSizedEditBox ) + + public: + virtual MyGUI::IntSize getRequestedSize(); + virtual void setCaption(const MyGUI::UString& _value); + + protected: + virtual void setPropertyOverride(const std::string& _key, const std::string& _value); + }; + class AutoSizedButton : public AutoSizedWidget, public MyGUI::Button { MYGUI_RTTI_DERIVED( AutoSizedButton ) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0e4c3a6082..3da739e260 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -129,6 +129,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 86e65e99a9..765bf88a83 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -1,17 +1,36 @@ - + + + + + + - + - + + + + + + + + + + + + + + + @@ -127,12 +146,17 @@ - - - - + + + + + + + + + From f943580138209a27497e0613ab6914f5194a3589 Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 12 Mar 2013 17:44:22 +0000 Subject: [PATCH 0690/1483] Somehow manages to get from one cell to another, but this looks wrong... And I don't know how morrowind do it, because aitravel is completly buggy --- apps/openmw/mwmechanics/aitravel.cpp | 6 +++++- apps/openmw/mwmechanics/aitravel.hpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 09b0efad9c..3c2e29743a 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -169,9 +169,13 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + if(cellChange) std::cout << "cellChanged! \n"; //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; float yCell = 0; if (actor.getCell()->mCell->isExterior()) diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index a596f4c85d..3d220cb7e3 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -23,6 +23,9 @@ namespace MWMechanics float mY; float mZ; + int cellX; + int cellY; + bool isPathConstructed; std::list mPath; From 30f3fbac3ca97bed283ebf29b57b33c5b73b726b Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 12 Mar 2013 21:21:08 +0100 Subject: [PATCH 0691/1483] Fixed paths to OpenMW icons --- CMakeLists.txt | 36 ++++++++++++++++++------------------ files/launcher/launcher.rc | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9aabd60551..6e2c9b3c40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,10 +257,10 @@ set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1) # Set up Ogre plugin folder & debug suffix if (APPLE) - # Ogre on OS X doesn't use "_d" suffix (see Ogre's CMakeLists.txt) - add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="") + # Ogre on OS X doesn't use "_d" suffix (see Ogre's CMakeLists.txt) + add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="") else () - add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d") + add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d") endif() add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}") @@ -278,9 +278,9 @@ add_subdirectory(files/mygui) # Specify build paths if (APPLE) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") else (APPLE) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") endif (APPLE) # Other files @@ -334,7 +334,7 @@ if(DPKG_PROGRAM) #Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "share/applications/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "share/pixmaps/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "share/pixmaps/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") #Install global configuration files INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") @@ -355,7 +355,7 @@ if(DPKG_PROGRAM) Data files from the original game is required to run it.") SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") - SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") + SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") @@ -510,10 +510,10 @@ if (WIN32) 4986 # Undocumented warning that occurs in the crtdbg.h file 4996 # Function was declared deprecated - # cause by ogre extensivly - 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' - 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' - 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' + # cause by ogre extensivly + 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' + 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' + 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type @@ -525,7 +525,7 @@ if (WIN32) 4309 # Variable overflow, trying to store 128 in a signed char for example 4355 # Using 'this' in member initialization list 4701 # Potentially uninitialized local variable used - 4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt + 4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt ) foreach(d ${WARNINGS_DISABLE}) @@ -536,12 +536,12 @@ if (WIN32) set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) if (BUILD_LAUNCHER) - set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) - endif (BUILD_LAUNCHER) + set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) + endif (BUILD_LAUNCHER) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) - if (BUILD_BSATOOL) + if (BUILD_BSATOOL) set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS}) - endif (BUILD_BSATOOL) + endif (BUILD_BSATOOL) if (BUILD_ESMTOOL) set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif (BUILD_ESMTOOL) @@ -666,9 +666,9 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) IF(BUILD_LAUNCHER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER) - IF(BUILD_BSATOOL) + IF(BUILD_BSATOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_BSATOOL) + ENDIF(BUILD_BSATOOL) IF(BUILD_ESMTOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESMTOOL) diff --git a/files/launcher/launcher.rc b/files/launcher/launcher.rc index efe86e4da4..df2121f469 100644 --- a/files/launcher/launcher.rc +++ b/files/launcher/launcher.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "resources/images/openmw.ico" +IDI_ICON1 ICON DISCARDABLE "images/openmw.ico" From 599207a92d6d0423d5894ed1ba4d51e09f2d7dad Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Mar 2013 01:00:47 +0100 Subject: [PATCH 0692/1483] Transparency sorting should be enabled only when alpha blending is enabled --- components/nifogre/ogrenifloader.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 30c71023bc..67919f7044 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -743,8 +743,6 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String blend_mode += getBlendFactor((alphaFlags>>5)&0xf); instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); } - else - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); if((alphaFlags>>9)&1) { @@ -754,9 +752,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String reject += Ogre::StringConverter::toString(alphaTest); instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } + else + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(!((alphaFlags>>13)&1) ? "force" : "off"))); + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( + ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); From 00deff1758dea912605013c5ae37028ea1269110 Mon Sep 17 00:00:00 2001 From: vorenon Date: Wed, 13 Mar 2013 09:37:14 +0100 Subject: [PATCH 0693/1483] fixed path for launcher icons --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e2c9b3c40..574ff555b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,8 +409,8 @@ if(WIN32) SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") - SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico") - SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico") + SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico") + SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico") SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp") SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe") @@ -680,7 +680,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) ENDIF(BUILD_OPENCS) # Install icon and .desktop - INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications") # Install global configuration files From fdcbdbf35df7f3401b5db0dd990927e1479387eb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Mar 2013 19:44:34 +0100 Subject: [PATCH 0694/1483] Rewrote layout tooltips to use the new box layout system, fixes word wrapping delay --- apps/openmw/mwgui/tooltips.cpp | 68 ++++------- apps/openmw/mwgui/widgets.cpp | 2 + files/mygui/openmw_tooltips.layout | 179 ++++++++++++++--------------- 3 files changed, 112 insertions(+), 137 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 8dcf398ca5..8eb0336a79 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -44,6 +44,11 @@ ToolTips::ToolTips(MWBase::WindowManager* windowManager) : mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); mRemainingDelay = mDelay; + + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) + { + mMainWidget->getChildAt(i)->setVisible(false); + } } void ToolTips::setEnabled(bool enabled) @@ -115,7 +120,7 @@ void ToolTips::onFrame(float frameDuration) } else { - mHorizontalScrollIndex = 0; + mHorizontalScrollIndex = 0; mRemainingDelay = mDelay; } mLastMouseX = mousePos.left; @@ -215,14 +220,6 @@ void ToolTips::onFrame(float frameDuration) getWidget(tooltip, focus->getUserString("ToolTipLayout")); tooltip->setVisible(true); - if (!tooltip->isUserString("DontResize")) - { - tooltip->setCoord(0, 0, 450, 300); // this is the maximum width of the tooltip before it starts word-wrapping - - tooltipSize = MyGUI::IntSize(0, tooltip->getSize().height); - } - else - tooltipSize = tooltip->getSize(); std::map userStrings = focus->getUserStrings(); for (std::map::iterator it = userStrings.begin(); @@ -243,32 +240,8 @@ void ToolTips::onFrame(float frameDuration) w->setProperty(propertyKey, it->second); } - for (unsigned int i=0; igetChildCount(); ++i) - { - MyGUI::Widget* w = tooltip->getChildAt(i); + tooltipSize = tooltip->getSize(); - if (w->isUserString("AutoResizeHorizontal")) - { - MyGUI::TextBox* text = w->castType(); - tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + text->getTextSize().width + 8); - } - else if (!tooltip->isUserString("DontResize")) - tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + w->getWidth() + 8); - - if (w->isUserString("AutoResizeVertical")) - { - MyGUI::TextBox* text = w->castType(); - int height = text->getTextSize().height; - if (height > w->getHeight()) - { - tooltipSize += MyGUI::IntSize(0, height - w->getHeight()); - } - if (height < w->getHeight()) - { - tooltipSize -= MyGUI::IntSize(0, w->getHeight() - height); - } - } - } tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); } else @@ -509,20 +482,21 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) captionSize.height); //if its too long we do hscroll with the caption - if (captionSize.width > maximumWidth){ - mHorizontalScrollIndex = mHorizontalScrollIndex + 2; - if (mHorizontalScrollIndex > captionSize.width){ - mHorizontalScrollIndex = -totalSize.width; - } - int horizontal_scroll = mHorizontalScrollIndex; - if (horizontal_scroll < 40){ - horizontal_scroll = 40; - }else{ - horizontal_scroll = 80 - mHorizontalScrollIndex; - } - captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); + if (captionSize.width > maximumWidth) + { + mHorizontalScrollIndex = mHorizontalScrollIndex + 2; + if (mHorizontalScrollIndex > captionSize.width){ + mHorizontalScrollIndex = -totalSize.width; + } + int horizontal_scroll = mHorizontalScrollIndex; + if (horizontal_scroll < 40){ + horizontal_scroll = 40; + }else{ + horizontal_scroll = 80 - mHorizontalScrollIndex; + } + captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); } else { - captionWidget->setPosition (captionWidget->getPosition() + padding); + captionWidget->setPosition (captionWidget->getPosition() + padding); } textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index b0f7e6293b..2590990172 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -588,6 +588,8 @@ void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::s MyGUI::IntSize AutoSizedEditBox::getRequestedSize() { + if (getAlign().isHStretch()) + throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")"); return MyGUI::IntSize(getSize().width, getTextSize().height); } diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index 514d1a25b3..f554e2b0d5 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -5,124 +5,124 @@ - - - + + + - + - - - - + + + - + - - + - - - - + + + - + - - + - - - + - - - + + + - + + + + + + + - + - - - - + + + - + + + - - - + + + - + - - - - + + + - + + + - - - + + + + + + + + + - - - - - - + - - - - + @@ -135,37 +135,36 @@ - - + + + - + + - - - + + + + + + + + + + + - - - - - - + - - - - - - @@ -181,43 +180,43 @@ - - + + + - + - - - - + + + - + + - - - + + + + + + + + + - - - - - - + - - From 0223df4dfcec3a4f4d4c324818408671cdc24e6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Mar 2013 19:45:22 +0100 Subject: [PATCH 0695/1483] Fix invalid cast exception in the spell creation dialog --- apps/openmw/mwgui/spellcreationdialog.cpp | 7 +++++-- apps/openmw/mwgui/spellcreationdialog.hpp | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 8395864521..8a079e40ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -454,10 +454,13 @@ namespace MWGui mAvailableEffectsList->clear (); + int i=0; for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString()); + mButtonMapping[i] = *it; + ++i; } mAvailableEffectsList->adjustSize (); @@ -466,7 +469,6 @@ namespace MWGui std::string name = MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString(); MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); - w->setUserData(*it); ToolTips::createMagicEffectToolTip (w, *it); } @@ -518,7 +520,8 @@ namespace MWGui return; } - short effectId = *sender->getUserData(); + int buttonId = *sender->getUserData(); + short effectId = mButtonMapping[buttonId]; for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 4d27ec1c6f..393d9c3ec2 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -88,6 +88,8 @@ namespace MWGui protected: + std::map mButtonMapping; // maps button ID to effect ID + Widgets::MWList* mAvailableEffectsList; MyGUI::ScrollView* mUsedEffectsView; From c4a42f2e1f6edffe6d6610f64df2ad773f30a8a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Mar 2013 23:17:25 +0100 Subject: [PATCH 0696/1483] Fix infinite recursion on shutdown caused by incorrect onWidgetDestroy listener --- apps/openmw/mwgui/widgets.cpp | 10 ---------- apps/openmw/mwgui/widgets.hpp | 2 -- 2 files changed, 12 deletions(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 2590990172..e822e047ea 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -749,11 +749,6 @@ void HBox::onWidgetCreated(MyGUI::Widget* _widget) align(); } -void HBox::onWidgetDestroy(MyGUI::Widget* _widget) -{ - align(); -} - MyGUI::IntSize HBox::getRequestedSize () { MyGUI::IntSize size(0,0); @@ -905,8 +900,3 @@ void VBox::onWidgetCreated(MyGUI::Widget* _widget) { align(); } - -void VBox::onWidgetDestroy(MyGUI::Widget* _widget) -{ - align(); -} diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index d2bcb69257..784537c42a 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -403,7 +403,6 @@ namespace MWGui virtual void setPropertyOverride(const std::string& _key, const std::string& _value); virtual void onWidgetCreated(MyGUI::Widget* _widget); - virtual void onWidgetDestroy(MyGUI::Widget* _widget); }; class VBox : public Box, public MyGUI::Widget @@ -421,7 +420,6 @@ namespace MWGui virtual void setPropertyOverride(const std::string& _key, const std::string& _value); virtual void onWidgetCreated(MyGUI::Widget* _widget); - virtual void onWidgetDestroy(MyGUI::Widget* _widget); }; } } From 84afd873211f396d0e036824a50f788f4d20e445 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 03:04:02 +0100 Subject: [PATCH 0697/1483] Placeable objects should not collide unless they have a NiRootCollisionNode --- apps/openmw/mwclass/apparatus.cpp | 2 +- apps/openmw/mwclass/armor.cpp | 2 +- apps/openmw/mwclass/book.cpp | 2 +- apps/openmw/mwclass/clothing.cpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 2 +- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 2 +- apps/openmw/mwclass/misc.cpp | 2 +- apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwclass/weapon.cpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 16 +++++++++++----- apps/openmw/mwworld/physicssystem.hpp | 2 +- components/nifbullet/bulletnifloader.cpp | 16 ++++++++-------- components/nifbullet/bulletnifloader.hpp | 2 +- libs/openengine/bullet/BulletShapeLoader.cpp | 2 +- libs/openengine/bullet/BulletShapeLoader.h | 6 ++++-- libs/openengine/bullet/physic.cpp | 7 ++++++- libs/openengine/bullet/physic.hpp | 3 ++- 20 files changed, 46 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 2c561eb858..851a5ae360 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -35,7 +35,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 654cb87fd6..fdf211c28a 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -38,7 +38,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Armor::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 6c3b7b86c3..4e29fa6845 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -33,7 +33,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Book::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 892ac091ce..dfced6daa8 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -36,7 +36,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Clothing::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index bbba45df58..14cf6ff6f9 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -46,7 +46,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 200f6e2d4a..7466657725 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -50,7 +50,7 @@ namespace MWClass const std::string &model = ref->mBase->mModel; if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,ref->mBase->mData.mFlags & ESM::Light::Carry); if (!ref->mBase->mSound.empty()) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, MWBase::SoundManager::Play_Loop); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 7e909437cf..665644736d 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -36,7 +36,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index d43a44359f..07e41bcfa6 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -39,7 +39,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 0ac78a2e40..37461ed905 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -38,7 +38,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Potion::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index a28be17e7e..5b1b55bd31 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -36,7 +36,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Probe::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 39a7f65e07..d6afe93198 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -34,7 +34,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Repair::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index d8c11558cc..475c08ccbf 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -36,7 +36,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Weapon::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7edd202935..28f3317065 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -364,14 +364,15 @@ namespace MWWorld mEngine->removeHeightField(x, y); } - void PhysicsSystem::addObject (const Ptr& ptr) + void PhysicsSystem::addObject (const Ptr& ptr, bool placeable) { std::string mesh = MWWorld::Class::get(ptr).getModel(ptr); Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); handleToMesh[node->getName()] = mesh; - OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody(mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation()); - OEngine::Physic::RigidBody* raycastingBody = mEngine->createAndAdjustRigidBody - (mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, true); + OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody( + mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, false, placeable); + OEngine::Physic::RigidBody* raycastingBody = mEngine->createAndAdjustRigidBody( + mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, true, placeable); mEngine->addRigidBody(body, true, raycastingBody); } @@ -440,8 +441,13 @@ namespace MWWorld const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { + bool placeable = false; + if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,true)) + placeable = body->mPlaceable; + else if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,false)) + placeable = body->mPlaceable; removeObject(handle); - addObject(ptr); + addObject(ptr, placeable); } if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 60c8246ae3..2e48be4079 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -29,7 +29,7 @@ namespace MWWorld PhysicsSystem (OEngine::Render::OgreRenderer &_rend); ~PhysicsSystem (); - void addObject (const MWWorld::Ptr& ptr); + void addObject (const MWWorld::Ptr& ptr, bool placeable=false); void addActor (const MWWorld::Ptr& ptr); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index af1243346a..04ac3d1410 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -109,17 +109,17 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - bool hasCollisionNode = hasRootCollisionNode(node); + cShape->mHasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(mesh1, node,0,hasCollisionNode,false,false); + handleNode(mesh1, node,0,false,false); if(mBoundingBox != NULL) { cShape->mCollisionShape = mBoundingBox; delete mesh1; } - else if (mHasShape && !cShape->mIgnore && cShape->mCollide) + else if (mHasShape && cShape->mCollide) { cShape->mCollisionShape = new TriangleMeshShape(mesh1,true); } @@ -136,14 +136,14 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) btTriangleMesh* mesh2 = new btTriangleMesh(); - handleNode(mesh2, node,0,hasCollisionNode,true,true); + handleNode(mesh2, node,0,true,true); if(mBoundingBox != NULL) { cShape->mRaycastingShape = mBoundingBox; delete mesh2; } - else if (mHasShape && !cShape->mIgnore) + else if (mHasShape) { cShape->mRaycastingShape = new TriangleMeshShape(mesh2,true); } @@ -174,7 +174,7 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) } void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *node, int flags, - bool hasCollisionNode, bool isCollisionNode, + bool isCollisionNode, bool raycasting) { // Accumulate the flags from all the child nodes. This works for all @@ -223,7 +223,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * } } - if (isCollisionNode || (!hasCollisionNode && !raycasting)) + if (isCollisionNode || (!cShape->mHasCollisionNode && !raycasting)) { if(node->hasBounds) { @@ -246,7 +246,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(mesh, list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycasting); + handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting); } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 9cb5a3e86e..c231b75b68 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -82,7 +82,7 @@ private: /** *Parse a node. */ - void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycasting); + void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting); /** *Helper function diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 8744c4e4d6..431d2b91b4 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -19,8 +19,8 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) */ mCollisionShape = NULL; mRaycastingShape = NULL; + mHasCollisionNode = false; mCollide = true; - mIgnore = false; createParamDictionary("BulletShape"); } diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index fa03b02766..a6591010ad 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -35,12 +35,14 @@ public: btCollisionShape* mCollisionShape; btCollisionShape* mRaycastingShape; + // Whether or not a NiRootCollisionNode was present in the .nif. If there is none, the collision behaviour + // depends on object type, so we need to expose this variable. + bool mHasCollisionNode; + Ogre::Vector3 mBoxTranslation; Ogre::Quaternion mBoxRotation; //this flag indicate if the shape is used for collision or if it's for raycasting only. bool mCollide; - - bool mIgnore; }; /** diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index c4947af1e1..6e6490a411 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -144,6 +144,7 @@ namespace Physic RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name) : btRigidBody(CI) , mName(name) + , mPlaceable(false) { } @@ -368,7 +369,7 @@ namespace Physic RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting) + Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting, bool placeable) { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; @@ -378,6 +379,9 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); + if (placeable && !raycasting && shape->mCollisionShape && !shape->mHasCollisionNode) + return NULL; + if (!shape->mCollisionShape && !raycasting) return NULL; if (!shape->mRaycastingShape && raycasting) @@ -395,6 +399,7 @@ namespace Physic btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo (0,newMotionState, raycasting ? shape->mRaycastingShape : shape->mCollisionShape); RigidBody* body = new RigidBody(CI,name); + body->mPlaceable = placeable; if(scaledBoxTranslation != 0) *scaledBoxTranslation = shape->mBoxTranslation * scale; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 367db261fd..6ce4edba35 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -164,6 +164,7 @@ namespace Physic RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name); virtual ~RigidBody(); std::string mName; + bool mPlaceable; }; struct HeightField @@ -197,7 +198,7 @@ namespace Physic */ RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool raycasting=false); + Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool raycasting=false, bool placeable=false); /** * Adjusts a rigid body to the right position and rotation From 3d34fea21ef4633afc0540f9f3ef0ae55294404c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 14 Mar 2013 13:51:46 +0100 Subject: [PATCH 0698/1483] updated changelog --- readme.txt | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/readme.txt b/readme.txt index f5997cd256..4fa7bb0795 100644 --- a/readme.txt +++ b/readme.txt @@ -94,6 +94,81 @@ Allowed options: CHANGELOG +0.22.0 + +Bug #311: Potential infinite recursion in script compiler +Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit. +Bug #382: Weird effect in 3rd person on water +Bug #387: Always use detailed shape for physics raycasts +Bug #420: Potion/ingredient effects do not stack +Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips +Bug #434/Bug #605: Object movement between cells not properly implemented +Bug #455: Animation doesn't move creature's bounding box +Bug #502: Duplicate player collision model at origin +Bug #509: Dialogue topic list shifts inappropriately +Bug #513: Sliding stairs +Bug #515: Launcher does not support non-latin strings +Bug #525: Race selection preview camera wrong position +Bug #526: Attributes / skills should not go below zero +Bug #529: Class and Birthsign menus options should be preselected +Bug #530: Lock window button graphic missing +Bug #532: Missing map menu graphics +Bug #545: ESX selector does not list ESM files properly +Bug #547: Global variables of type short are read incorrectly +Bug #550: Invisible meshes collision and tooltip +Bug #551: Performance drop when loading multiple ESM files +Bug #552: Don't list CG in options if it is not available +Bug #555: Character creation windows "OK" button broken +Bug #558: Segmentation fault when Alt-tabbing with console opened +Bug #559: Dialog window should not be available before character creation is finished +Bug #560: Tooltip borders should be stretched +Bug #562: Sound should not be played when an object cannot be picked up +Bug #565: Water animation speed + timescale +Bug #572: Better Bodies' textures don't work +Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod) +Bug #574: Moving left/right should not cancel auto-run +Bug #575: Crash entering the Chamber of Song +Bug #576: Missing includes +Bug #577: Left Gloves Addon causes ESMReader exception +Bug #579: Unable to open container "Kvama Egg Sack" +Bug #581: Mimicking vanilla Morrowind water +Bug #583: Gender not recognized +Bug #586: Wrong char gen behaviour +Bug #587: "End" script statements with spaces don't work +Bug #589: Closing message boxes by pressing the activation key +Bug #590: Ugly Dagoth Ur rendering +Bug #591: Race selection issues +Bug #593: Persuasion response should be random +Bug #595: Footless guard +Bug #599: Waterfalls are invisible from a certain distance +Bug #600: Waterfalls rendered incorrectly, cut off by water +Bug #607: New beast bodies mod crashes +Bug #608: Crash in cell "Mournhold, Royal Palace" +Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt +Bug #613: Messagebox causing assert to fail +Bug #615: Meshes invisible from above water +Bug #617: Potion effects should be hidden until discovered +Bug #619: certain moss hanging from tree has rendering bug +Bug #621: Batching bloodmoon's trees +Bug #623: NiMaterialProperty alpha unhandled +Bug #628: Launcher in latest master crashes the game +Feature #29: Allow ESPs and multiple ESMs +Feature #94: Finish class selection-dialogue +Feature #149: Texture Alphas +Feature #237: Run Morrowind-ini importer from launcher +Feature #286: Update Active Spell Icons +Feature #334: Swimming animation +Feature #335: Walking animation +Feature #360: Proper collision shapes for NPCs and creatures +Feature #367: Lights that behave more like original morrowind implementation +Feature #477: Special local scripting variables +Feature #528: Message boxes should close when enter is pressed under certain conditions. +Feature #543: Add bsa files to the settings imported by the ini importer +Feature #594: coordinate space and utility functions +Feature #625: Zoom in vanity mode +Task #464: Refactor launcher ESX selector into a re-usable component +Task #624: Unified implementation of type-variable sub-records + 0.21.0 Bug #253: Dialogs don't work for Russian version of Morrowind From d30b38f336f60cbb8183949e9365f64f96bd2db5 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 14 Mar 2013 19:28:17 +0400 Subject: [PATCH 0699/1483] fix Store::eraseStatic() --- apps/openmw/mwworld/store.hpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 586e407ff0..20646e6dad 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,18 +187,17 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); - // delete from the static part of mShared - typename std::vector::iterator sharedIter = mShared.begin(); - for (; sharedIter != (mShared.begin()+mStatic.size()); ++sharedIter) { - if((*sharedIter)->mId == item.mId) { - mShared.erase(sharedIter); - break; - } - } - typename std::map::iterator it = mStatic.find(item.mId); if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { + // delete from the static part of mShared + typename std::vector::iterator sharedIter = mShared.begin(); + for (; sharedIter != (mShared.begin()+mStatic.size()); ++sharedIter) { + if((*sharedIter)->mId == item.mId) { + mShared.erase(sharedIter); + break; + } + } mStatic.erase(it); } From 80804fac351fedcde4735753c7ae2db461a80628 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 14 Mar 2013 17:16:37 +0000 Subject: [PATCH 0700/1483] check if the NPC is close from a non loaded cell. If yes, AITravel is simply ended. --- apps/openmw/mwmechanics/aitravel.cpp | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 3c2e29743a..57b9f66dde 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -7,6 +7,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "movement.hpp" +#include "../mwworld/player.hpp" #include #include @@ -167,13 +168,35 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - if(cellChange) std::cout << "cellChanged! \n"; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; @@ -190,7 +213,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); mPath = getPath(start,end,graph); - if(mPath.empty()) std::cout << "graph doesn't find any way..."; + ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; @@ -200,7 +223,6 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(mPath.empty()) { - std::cout << "pathc empty"; MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } @@ -211,7 +233,6 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) if(mPath.empty()) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - std::cout << "emptypath!"; return true; } nextPoint = *mPath.begin(); From e30af28860d82c5a85a7c1ef052fde6d01ab5ed9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 19:03:42 +0100 Subject: [PATCH 0701/1483] Markers should still have collision if they have a NiRootCollisionNode --- components/nifbullet/bulletnifloader.cpp | 19 +++++++++---------- components/nifbullet/bulletnifloader.hpp | 2 +- components/nifogre/ogrenifloader.cpp | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 04ac3d1410..08625ee9cb 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -112,7 +112,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) cShape->mHasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(mesh1, node,0,false,false); + handleNode(mesh1, node,0,false,false,false); if(mBoundingBox != NULL) { @@ -136,7 +136,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) btTriangleMesh* mesh2 = new btTriangleMesh(); - handleNode(mesh2, node,0,true,true); + handleNode(mesh2, node,0,true,true,false); if(mBoundingBox != NULL) { @@ -175,7 +175,7 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *node, int flags, bool isCollisionNode, - bool raycasting) + bool raycasting, bool isMarker) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -186,14 +186,12 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * else isCollisionNode = isCollisionNode && (node->recType != Nif::RC_RootCollisionNode); - // Marker objects: no collision + // Marker objects /// \todo don't do this in the editor std::string nodename = node->name; Misc::StringUtils::toLower(nodename); if (nodename.find("marker") != std::string::npos) - { - return; - } + isMarker = true; // Check for extra data Nif::Extra const *e = node; @@ -219,11 +217,12 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * // 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; + isMarker = true; } } - if (isCollisionNode || (!cShape->mHasCollisionNode && !raycasting)) + if ( (isCollisionNode || (!cShape->mHasCollisionNode && !raycasting)) + && (!isMarker || (cShape->mHasCollisionNode && !raycasting))) { if(node->hasBounds) { @@ -246,7 +245,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting); + handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting, isMarker); } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index c231b75b68..7958f3b7cb 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -82,7 +82,7 @@ private: /** *Parse a node. */ - void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting); + void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting, bool isMarker); /** *Helper function diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 30c71023bc..3fc82f73ab 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1113,7 +1113,7 @@ public: { // Marker objects. These are only visible in the // editor. - flags |= 0x01; + return; } } e = e->extra; From 9efb073617cf41f66f774c9453574594fbcf2870 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 14 Mar 2013 18:05:00 +0000 Subject: [PATCH 0702/1483] clean up + correct a bug --- apps/openmw/mwmechanics/aitravel.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 57b9f66dde..94f6fd8928 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -40,8 +40,8 @@ float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) { - if(!grid) throw std::exception("NULL PathGrid!"); - if(grid->mPoints.empty()) throw std::exception("empty PathGrid!"); + if(!grid) return -1; + if(grid->mPoints.empty()) return -1; float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; @@ -54,7 +54,6 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) i0 = i; } } - std::cout << "distance:: " << m << "\n"; return i0; } @@ -175,7 +174,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) { - int sideX = sgn(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX); + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) { @@ -185,7 +184,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) { - int sideY = sgn(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY); + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) { @@ -193,10 +192,9 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } } - //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; @@ -210,9 +208,11 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); - PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); - - mPath = getPath(start,end,graph); + if(start != -1 && end != -1) + { + PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); + mPath = getPath(start,end,graph); + } ESM::Pathgrid::Point dest; dest.mX = mX; From beab20cb42bea88073abff173b6e2410327f0796 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 19:53:57 +0100 Subject: [PATCH 0703/1483] Fix message boxes not opening if they opened as a result of object activation --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f18c02a0e8..d9746fcfe4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -180,12 +180,12 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - activate(); if( MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) { // Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button MWBase::Environment::get().getWindowManager()->enterPressed(); } + activate(); break; case A_Journal: toggleJournal (); From 1ff26b2aa6d3d3594c2cb15d606468c5f032ceba Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 14 Mar 2013 19:59:43 +0100 Subject: [PATCH 0704/1483] updated changelog one more --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 4fa7bb0795..af00b828b6 100644 --- a/readme.txt +++ b/readme.txt @@ -152,6 +152,7 @@ Bug #619: certain moss hanging from tree has rendering bug Bug #621: Batching bloodmoon's trees Bug #623: NiMaterialProperty alpha unhandled Bug #628: Launcher in latest master crashes the game +Bug #633: Crash on startup: Better Heads Feature #29: Allow ESPs and multiple ESMs Feature #94: Finish class selection-dialogue Feature #149: Texture Alphas From 2d8f0949a475d7dcf7b7854d9f4c601c46f8a954 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 20:27:16 +0100 Subject: [PATCH 0705/1483] Always run key (Y) --- apps/openmw/mwclass/npc.cpp | 18 ++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 3 +++ apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- apps/openmw/mwinput/inputmanagerimp.hpp | 2 +- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ apps/openmw/mwworld/player.cpp | 4 ++-- 7 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d4e5e5cd67..77b53ff1d9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -322,6 +322,24 @@ namespace MWClass return false; } + bool Npc::getForceStance(const MWWorld::Ptr& ptr, Stance stance) const + { + MWMechanics::NpcStats& stats = getNpcStats (ptr); + + switch (stance) + { + case Run: + return stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun); + case Sneak: + return stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak); + + case Combat: + return false; + } + + return false; + } + float Npc::getSpeed(const MWWorld::Ptr& ptr) const { const MWBase::World *world = MWBase::Environment::get().getWorld(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f41edb0df6..4698a1b9f3 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -76,6 +76,9 @@ namespace MWClass virtual void setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. + virtual bool getForceStance (const MWWorld::Ptr& ptr, Stance stance) const; + ///< Check if a stance forced. + virtual void setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const; ///< Set or unset a stance. diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f18c02a0e8..72e9902837 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -193,7 +193,7 @@ namespace MWInput case A_AutoMove: toggleAutoMove (); break; - case A_ToggleWalk: + case A_AlwaysRun: toggleWalking (); break; case A_ToggleWeapon: @@ -768,6 +768,7 @@ namespace MWInput defaultKeyBindings[A_QuickKey10] = OIS::KC_0; defaultKeyBindings[A_Screenshot] = OIS::KC_SYSRQ; defaultKeyBindings[A_ToggleHUD] = OIS::KC_F12; + defaultKeyBindings[A_AlwaysRun] = OIS::KC_Y; std::map defaultMouseButtonBindings; defaultMouseButtonBindings[A_Inventory] = OIS::MB_Right; @@ -834,6 +835,7 @@ namespace MWInput descriptions[A_QuickKey8] = "sQuick8Cmd"; descriptions[A_QuickKey9] = "sQuick9Cmd"; descriptions[A_QuickKey10] = "sQuick10Cmd"; + descriptions[A_AlwaysRun] = "sAlways_Run"; if (descriptions[action] == "") return ""; // not configurable @@ -865,6 +867,7 @@ namespace MWInput ret.push_back(A_MoveRight); ret.push_back(A_TogglePOV); ret.push_back(A_Run); + ret.push_back(A_AlwaysRun); ret.push_back(A_Sneak); ret.push_back(A_Activate); ret.push_back(A_ToggleWeapon); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 8bb20b7bed..34c8327566 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -217,7 +217,7 @@ namespace MWInput A_CycleWeaponLeft,//Cycling through weapons A_CycleWeaponRight, A_ToggleSneak, //Toggles Sneak - A_ToggleWalk, //Toggle Walking/Running + A_AlwaysRun, //Toggle Walking/Running A_Sneak, A_QuickSave, diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 71b24b65dc..2bc4941a26 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -117,6 +117,11 @@ namespace MWWorld return false; } + bool Class::getForceStance (const Ptr& ptr, Stance stance) const + { + return false; + } + float Class::getSpeed (const Ptr& ptr) const { return 0; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1a6a16ca07..d36e3bc584 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -131,6 +131,9 @@ namespace MWWorld virtual void setForceStance (const Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. + virtual bool getForceStance (const Ptr& ptr, Stance stance) const; + ///< Check if a stance forced. + virtual void setStance (const Ptr& ptr, Stance stance, bool set) const; ///< Set or unset a stance. diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 03dd1abc79..5407e3a684 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -81,9 +81,9 @@ namespace MWWorld { MWWorld::Ptr ptr = getPlayer(); - bool running = MWWorld::Class::get (ptr).getStance (ptr, MWWorld::Class::Run, true); + bool running = MWWorld::Class::get (ptr).getForceStance(ptr, MWWorld::Class::Run); - MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); + MWWorld::Class::get (ptr).setForceStance(ptr, MWWorld::Class::Run, !running); } void Player::setSneak(bool sneak) From 5b943a965f5334356682511420715d35f522c847 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 21:08:19 +0100 Subject: [PATCH 0706/1483] Handle always run in the inputmanager, instead of using forced stance. --- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +++++---- apps/openmw/mwinput/inputmanagerimp.hpp | 1 + apps/openmw/mwworld/class.cpp | 5 ----- apps/openmw/mwworld/class.hpp | 3 --- apps/openmw/mwworld/player.cpp | 9 --------- apps/openmw/mwworld/player.hpp | 1 - 7 files changed, 7 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 4698a1b9f3..bd624bd373 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -84,7 +84,7 @@ namespace MWClass virtual bool getStance (const MWWorld::Ptr& ptr, Stance stance, bool ignoreForce = false) const; - ////< Check if a stance is active or not. + ///< Check if a stance is active or not. virtual float getSpeed (const MWWorld::Ptr& ptr) const; ///< Return movement speed. diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 72e9902837..006729b337 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -55,6 +55,7 @@ namespace MWInput , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) + , mAlwaysRunActive(false) { Ogre::RenderWindow* window = mOgre.getWindow (); size_t windowHnd; @@ -315,10 +316,10 @@ namespace MWInput else mPlayer.setUpDown (0); - if(actionIsActive(A_Run)) - mPlayer.setRunState(true); + if (mAlwaysRunActive) + mPlayer.setRunState(!actionIsActive(A_Run)); else - mPlayer.setRunState(false); + mPlayer.setRunState(actionIsActive(A_Run)); // if player tried to start moving, but can't (due to being overencumbered), display a notification. if (triedToMove) @@ -699,7 +700,7 @@ namespace MWInput void InputManager::toggleWalking() { if (mWindows.isGuiMode()) return; - mPlayer.toggleRunning(); + mAlwaysRunActive = !mAlwaysRunActive; } // Exit program now button (which is disabled in GUI mode) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 34c8327566..e181fb351d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -152,6 +152,7 @@ namespace MWInput int mMouseWheel; bool mDebug; bool mUserFileExists; + bool mAlwaysRunActive; std::map mControlSwitch; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2bc4941a26..71b24b65dc 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -117,11 +117,6 @@ namespace MWWorld return false; } - bool Class::getForceStance (const Ptr& ptr, Stance stance) const - { - return false; - } - float Class::getSpeed (const Ptr& ptr) const { return 0; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index d36e3bc584..1a6a16ca07 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -131,9 +131,6 @@ namespace MWWorld virtual void setForceStance (const Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. - virtual bool getForceStance (const Ptr& ptr, Stance stance) const; - ///< Check if a stance forced. - virtual void setStance (const Ptr& ptr, Stance stance, bool set) const; ///< Set or unset a stance. diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 5407e3a684..0dc8b37eff 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -77,15 +77,6 @@ namespace MWWorld MWWorld::Class::get(ptr).setStance(ptr, MWWorld::Class::Run, run); } - void Player::toggleRunning() - { - MWWorld::Ptr ptr = getPlayer(); - - bool running = MWWorld::Class::get (ptr).getForceStance(ptr, MWWorld::Class::Run); - - MWWorld::Class::get (ptr).setForceStance(ptr, MWWorld::Class::Run, !running); - } - void Player::setSneak(bool sneak) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 5f2fc3a08b..d82d3fc329 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -66,7 +66,6 @@ namespace MWWorld void setUpDown(int value); void setRunState(bool run); - void toggleRunning(); void setSneak(bool sneak); }; } From b36295cbb3b87d45c78bcc8893da4eef25525d44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 21:10:22 +0100 Subject: [PATCH 0707/1483] Removed a leftover --- apps/openmw/mwclass/npc.cpp | 18 ------------------ apps/openmw/mwclass/npc.hpp | 3 --- 2 files changed, 21 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 77b53ff1d9..d4e5e5cd67 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -322,24 +322,6 @@ namespace MWClass return false; } - bool Npc::getForceStance(const MWWorld::Ptr& ptr, Stance stance) const - { - MWMechanics::NpcStats& stats = getNpcStats (ptr); - - switch (stance) - { - case Run: - return stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun); - case Sneak: - return stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak); - - case Combat: - return false; - } - - return false; - } - float Npc::getSpeed(const MWWorld::Ptr& ptr) const { const MWBase::World *world = MWBase::Environment::get().getWorld(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index bd624bd373..51e93636d3 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -76,9 +76,6 @@ namespace MWClass virtual void setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. - virtual bool getForceStance (const MWWorld::Ptr& ptr, Stance stance) const; - ///< Check if a stance forced. - virtual void setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const; ///< Set or unset a stance. From 7ab236337b89545e129da7fe2e6439d7e274ab33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 21:33:00 +0100 Subject: [PATCH 0708/1483] Dialogue responses should be random only for persuasion results --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +++--- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 35f0c94937..5258bb8a05 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -241,7 +241,7 @@ namespace MWDialogue } } - void DialogueManager::executeTopic (const std::string& topic) + void DialogueManager::executeTopic (const std::string& topic, bool randomResponse) { Filter filter (mActor, mChoice, mTalkedTo); @@ -256,7 +256,7 @@ namespace MWDialogue if (!infos.empty()) { - const ESM::DialInfo* info = infos[std::rand() % infos.size()]; + const ESM::DialInfo* info = infos[randomResponse ? std::rand() % infos.size() : 0]; parseText (info->mResponse); @@ -505,7 +505,7 @@ namespace MWDialogue text = "Bribe"; } - executeTopic (text + (success ? " Success" : " Fail")); + executeTopic (text + (success ? " Success" : " Fail"), true); } int DialogueManager::getTemporaryDispositionChange() const diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 1ca2ae5ebc..0c0299619c 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -48,7 +48,7 @@ namespace MWDialogue void printError (const std::string& error); - void executeTopic (const std::string& topic); + void executeTopic (const std::string& topic, bool randomResponse=false); public: From 3e9cd0e2e33e1cc1306dc9be8eababb5d1106a74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 22:33:51 +0100 Subject: [PATCH 0709/1483] Fix the back button on generate class result dialog advancing creation stage --- apps/openmw/mwgui/charactercreation.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index b98fd2bd9f..08d024f5c6 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -674,9 +674,6 @@ void CharacterCreation::showClassQuestionDialog() void CharacterCreation::onGenerateClassBack() { - if(mCreationStage < CSE_ClassChosen) - mCreationStage = CSE_ClassChosen; - mWM->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; From 110dd5d0eeb5db4ca295bd2ff2a0e4a50f6d56e0 Mon Sep 17 00:00:00 2001 From: pvdk Date: Fri, 15 Mar 2013 01:56:39 +0100 Subject: [PATCH 0710/1483] Possible fix for the resolutions not appearing with Direct3D Renderer --- apps/launcher/graphicspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 8d09cf3c03..19de88b67b 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -259,7 +259,7 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) for (opt_it = i->second.possibleValues.begin (); opt_it != i->second.possibleValues.end (); opt_it++, idx++) { - QRegExp resolutionRe(QString("(\\d+) x (\\d+)")); + QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); QString resolution = QString::fromStdString(*opt_it).simplified(); if (resolutionRe.exactMatch(resolution)) { From a74749099ee712777ef57bcc588b1ba47afaa423 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 15 Mar 2013 10:01:16 +0100 Subject: [PATCH 0711/1483] another changelog update --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index af00b828b6..bc3d63c789 100644 --- a/readme.txt +++ b/readme.txt @@ -153,6 +153,7 @@ Bug #621: Batching bloodmoon's trees Bug #623: NiMaterialProperty alpha unhandled Bug #628: Launcher in latest master crashes the game Bug #633: Crash on startup: Better Heads +Bug #636: Incorrect Char Gen Menu Behavior Feature #29: Allow ESPs and multiple ESMs Feature #94: Finish class selection-dialogue Feature #149: Texture Alphas From 521bebd2f403b3aaae6a10b50f563abc8f00df29 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 15 Mar 2013 10:17:30 +0100 Subject: [PATCH 0712/1483] Fallback system rewritten, added light fallbacks --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 4 - apps/openmw/mwrender/objects.cpp | 41 ++++--- apps/openmw/mwrender/objects.hpp | 17 +-- apps/openmw/mwrender/renderingmanager.cpp | 5 +- apps/openmw/mwrender/renderingmanager.hpp | 4 +- apps/openmw/mwworld/fallback.cpp | 46 ++++++++ apps/openmw/mwworld/fallback.hpp | 17 +++ apps/openmw/mwworld/weather.cpp | 127 ++++++++-------------- apps/openmw/mwworld/weather.hpp | 10 +- apps/openmw/mwworld/worldimp.cpp | 24 +--- apps/openmw/mwworld/worldimp.hpp | 7 +- 12 files changed, 163 insertions(+), 141 deletions(-) create mode 100644 apps/openmw/mwworld/fallback.cpp create mode 100644 apps/openmw/mwworld/fallback.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8df2136e5e..0edc18afba 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -53,7 +53,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp + esmstore store recordcmp fallback ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6cd5b90b40..642291eefb 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -103,12 +103,8 @@ namespace MWBase virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual void setFallbackValues (const std::map& fallbackMap) = 0; - virtual std::string getFallback (const std::string& key) const = 0; - virtual std::string getFallback (const std::string& key, const std::string& def) const = 0; - virtual MWWorld::Player& getPlayer() = 0; virtual const MWWorld::ESMStore& getStore() const = 0; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index cb1dfa75be..23d35c65f0 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -16,16 +16,31 @@ #include "renderconst.hpp" using namespace MWRender; +float Objects::lightLinearValue() +{ + return mFallback->getFallbackFloat("LightAttenuation_LinearValue"); +} +float Objects::lightLinearRadiusMult() +{ + return mFallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); +} +float Objects::lightQuadraticValue() +{ + return mFallback->getFallbackFloat("LightAttenuation_QuadraticValue"); +} +float Objects::lightQuadraticRadiusMult() +{ + return mFallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); +} -/// \todo Replace these, once fallback values from the ini file are available. -float Objects::lightLinearValue = 3; -float Objects::lightLinearRadiusMult = 1; - -float Objects::lightQuadraticValue = 16; -float Objects::lightQuadraticRadiusMult = 1; - -bool Objects::lightOutQuadInLin = true; -bool Objects::lightQuadratic = false; +bool Objects::lightOutQuadInLin() +{ + return mFallback->getFallbackBool("LightAttenuation_OutQuadInLin"); +} +bool Objects::lightQuadratic() +{ + return mFallback->getFallbackBool("LightAttenuation_UseQuadratic"); +} int Objects::uniqueID = 0; @@ -269,14 +284,14 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre if (!quadratic) { - float r = radius * lightLinearRadiusMult; - float attenuation = lightLinearValue / r; + float r = radius * lightLinearRadiusMult(); + float attenuation = lightLinearValue() / r; light->setAttenuation(r*10, 0, attenuation, 0); } else { - float r = radius * lightQuadraticRadiusMult; - float attenuation = lightQuadraticValue / pow(r, 2); + float r = radius * lightQuadraticRadiusMult(); + float attenuation = lightQuadraticValue() / pow(r, 2); light->setAttenuation(r*10, 0, 0, attenuation); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 73e95a3c53..cfe5243061 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -5,6 +5,7 @@ #include #include +#include "../mwworld/fallback.hpp" namespace MWWorld { @@ -56,21 +57,21 @@ class Objects{ Ogre::SceneNode* mRootNode; bool mIsStatic; static int uniqueID; + MWWorld::Fallback* mFallback; + float lightLinearValue(); + float lightLinearRadiusMult(); - static float lightLinearValue; - static float lightLinearRadiusMult; + bool lightQuadratic(); + float lightQuadraticValue(); + float lightQuadraticRadiusMult(); - static bool lightQuadratic; - static float lightQuadraticValue; - static float lightQuadraticRadiusMult; - - static bool lightOutQuadInLin; + bool lightOutQuadInLin(); void clearSceneNode (Ogre::SceneNode *node); ///< Remove all movable objects from \a node. public: - Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {} + Objects(OEngine::Render::OgreRenderer& renderer, MWWorld::Fallback* fallback): mRenderer (renderer), mIsStatic(false), mFallback(fallback) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e6216b5372..3a15582ba0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -48,9 +48,10 @@ using namespace Ogre; namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) + const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback) : mRendering(_rend) - , mObjects(mRendering) + , mFallback(fallback) + , mObjects(mRendering,mFallback) , mActors(mRendering, this) , mAmbientMode(0) , mSunEnabled(0) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1777a72c33..fd43438ca5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -60,7 +60,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList public: RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine); + const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback); virtual ~RenderingManager(); void togglePOV() { @@ -220,6 +220,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList bool mSunEnabled; + MWWorld::Fallback* mFallback; + SkyManager* mSkyManager; OcclusionQuery* mOcclusionQuery; diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp new file mode 100644 index 0000000000..24ddc3db7b --- /dev/null +++ b/apps/openmw/mwworld/fallback.cpp @@ -0,0 +1,46 @@ +#include "fallback.hpp" +#include "boost/lexical_cast.hpp" +namespace MWWorld +{ + std::string Fallback::getFallbackString(const std::string& fall) const + { + std::map::const_iterator it; + if((it = mFallbackMap.find(fall)) == mFallbackMap.end()) + { + return ""; + } + return it->second; + } + float Fallback::getFallbackFloat(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback=="") + return 0; + else + return boost::lexical_cast(fallback); + } + bool Fallback::getFallbackBool(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback=="") + return false; + else + return boost::lexical_cast(fallback); + } + Ogre::ColourValue Fallback::getFallbackColour(const std::string& fall) const + { + std::string sum=getFallbackString(fall); + if(sum=="") + return Ogre::ColourValue(0,0,0); + else + { + std::string ret[3]; + unsigned int j=0; + for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); + } + } +} diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp new file mode 100644 index 0000000000..f2602c9776 --- /dev/null +++ b/apps/openmw/mwworld/fallback.hpp @@ -0,0 +1,17 @@ +#ifndef GAME_MWWORLD_FALLBACK_H +#define GAME_MWWORLD_FALLBACK_H +#include +namespace MWWorld +{ + class Fallback + { + const std::map mFallbackMap; + public: + Fallback(const std::map fallback):mFallbackMap(fallback){}; + std::string getFallbackString(const std::string& fall) const; + float getFallbackFloat(const std::string& fall) const; + bool getFallbackBool(const std::string& fall) const; + Ogre::ColourValue getFallbackColour(const std::string& fall) const; + }; +} +#endif diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 052ae4e028..2722bf80ea 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -4,7 +4,6 @@ #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" @@ -19,100 +18,68 @@ using namespace MWWorld; using namespace MWSound; #define lerp(x, y) (x * (1-factor) + y * factor) -std::string WeatherManager::getFallback (const std::string& key) const -{ - std::map::const_iterator it; - if((it = mFallback.find(key)) == mFallback.end()) - { - return ""; - } - return it->second; -} -std::string WeatherManager::getFallbackString(const std::string& fall) const -{ - return getFallback(fall); -} - -float WeatherManager::getFallbackFloat(const std::string& fall) const -{ - std::string fallback=getFallbackString(fall); - return boost::lexical_cast(fallback); -} - -ColourValue WeatherManager::getFallbackColour(const std::string& fall) const -{ - std::string sum; - std::string ret[3]; - sum=getFallback(fall); - unsigned int j=0; - for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); -} void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { - std::string upper=name; - upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); - weather.mTransitionDelta = getFallbackFloat("Weather_"+upper+"_Transition_Delta"); - weather.mSkySunriseColor=getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); - weather.mSkyDayColor = getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); - weather.mSkySunsetColor = getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); - weather.mSkyNightColor = getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); - weather.mFogSunriseColor = getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); - weather.mFogDayColor = getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); - weather.mFogSunsetColor = getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); - weather.mFogNightColor = getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); - weather.mAmbientSunriseColor = getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); - weather.mAmbientDayColor = getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); - weather.mAmbientSunsetColor = getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); - weather.mAmbientNightColor = getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); - weather.mSunSunriseColor = getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); - weather.mSunDayColor = getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); - weather.mSunSunsetColor = getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); - weather.mSunNightColor = getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); - weather.mSunDiscSunsetColor = getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); - weather.mLandFogDayDepth = getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); - weather.mLandFogNightDepth = getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); - weather.mWindSpeed = getFallbackFloat("Weather_"+upper+"_Wind_Speed"); - weather.mCloudSpeed = getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); - weather.mGlareView = getFallbackFloat("Weather_"+upper+"_Glare_View"); + std::string upper=name; + upper[0]=toupper(name[0]); + weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); + weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta"); + weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); + weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); + weather.mSkySunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); + weather.mSkyNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); + weather.mFogSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); + weather.mFogDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); + weather.mFogSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); + weather.mFogNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); + weather.mAmbientSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); + weather.mAmbientDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); + weather.mAmbientSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); + weather.mAmbientNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); + weather.mSunSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); + weather.mSunDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); + weather.mSunSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); + weather.mSunNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); + weather.mSunDiscSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); + weather.mLandFogDayDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); + weather.mLandFogNightDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); + weather.mWindSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Wind_Speed"); + weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); + weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); mWeatherSettings[name] = weather; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,const std::map& fallbackMap) : +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0), mMonth(0), mDay(0), - mTimePassed(0), mFallback(fallbackMap) + mTimePassed(0), mFallback(fallback) { mRendering = rendering; - //Globals - mThunderSoundID0 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = getFallbackFloat("Weather_Sunset_Duration"); - mWeatherUpdateTime = getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mThunderFrequency = getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); - mThunderSoundDelay = 0.25; - //Weather - Weather clear; - clear.mCloudTexture = "tx_sky_clear.dds"; - setFallbackWeather(clear,"clear"); + //Globals + mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); + mWeatherUpdateTime = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderSoundDelay = 0.25; + //Weather + Weather clear; + clear.mCloudTexture = "tx_sky_clear.dds"; + setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mCloudTexture = "tx_sky_cloudy.dds"; + cloudy.mCloudTexture = "tx_sky_cloudy.dds"; setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mCloudTexture = "tx_sky_foggy.dds"; + foggy.mCloudTexture = "tx_sky_foggy.dds"; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index b5bd0e10a0..ae0c2ca93b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -3,7 +3,7 @@ #include #include - +#include "fallback.hpp" namespace MWRender { class RenderingManager; @@ -112,7 +112,7 @@ namespace MWWorld class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*,const std::map& fallbackMap); + WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback); /** * Change the weather in the specified region @@ -141,11 +141,7 @@ namespace MWWorld private: float mHour; int mDay, mMonth; - std::map mFallback; - std::string getFallback (const std::string& key) const; - std::string getFallbackString(const std::string& fall) const; - float getFallbackFloat(const std::string& fall) const; - Ogre::ColourValue getFallbackColour(const std::string& fall) const; + MWWorld::Fallback* mFallback; void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a933713dd7..5a23aae972 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -154,24 +154,9 @@ namespace MWWorld mRendering->skyDisable(); } - void World::setFallbackValues (const std::map& fallbackMap) - { - mFallback = fallbackMap; - } - std::string World::getFallback (const std::string& key) const { - return getFallback(key, ""); - } - - std::string World::getFallback (const std::string& key, const std::string& def) const - { - std::map::const_iterator it; - if((it = mFallback.find(key)) == mFallback.end()) - { - return def; - } - return it->second; + return mFallback.getFallbackString(key); } World::World (OEngine::Render::OgreRenderer& renderer, @@ -181,17 +166,16 @@ namespace MWWorld ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), - mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride), - mFallback (fallbackMap) + mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride),mFallback(fallbackMap) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); - mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine); + mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); mPhysEngine->setSceneManager(renderer.getScene()); - mWeatherManager = new MWWorld::WeatherManager(mRendering,fallbackMap); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); int idx = 0; // NOTE: We might need to reserve one more for the running game / save. diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e06b89f600..526e68a77a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -10,6 +10,7 @@ #include "cells.hpp" #include "localscripts.hpp" #include "timestamp.hpp" +#include "fallback.hpp" #include "../mwbase/world.hpp" @@ -49,6 +50,7 @@ namespace MWWorld class World : public MWBase::World { + MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; MWWorld::WeatherManager* mWeatherManager; @@ -82,7 +84,6 @@ namespace MWWorld float mFaced1Distance; float mFaced2Distance; int mNumFacing; - std::map mFallback; unsigned long lastTick; Ogre::Timer mTimer; @@ -132,12 +133,8 @@ namespace MWWorld virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual void setFallbackValues (const std::map& fallbackMap); - virtual std::string getFallback (const std::string& key) const; - virtual std::string getFallback (const std::string& key, const std::string& def) const; - virtual Player& getPlayer(); virtual const MWWorld::ESMStore& getStore() const; From e1c6c3fe0259313e158dcc8333b960b00cd53687 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 15 Mar 2013 10:22:02 +0100 Subject: [PATCH 0713/1483] Tabulators deleted --- apps/openmw/mwworld/weather.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 2722bf80ea..db8787af7e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -70,16 +70,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); mThunderSoundDelay = 0.25; //Weather - Weather clear; - clear.mCloudTexture = "tx_sky_clear.dds"; - setFallbackWeather(clear,"clear"); + Weather clear; + clear.mCloudTexture = "tx_sky_clear.dds"; + setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mCloudTexture = "tx_sky_cloudy.dds"; + cloudy.mCloudTexture = "tx_sky_cloudy.dds"; setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mCloudTexture = "tx_sky_foggy.dds"; + foggy.mCloudTexture = "tx_sky_foggy.dds"; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; From 542c1bcc531307fa02171f9f6dd2574bd26bf691 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 15 Mar 2013 10:28:39 +0100 Subject: [PATCH 0714/1483] Some other tabulators deleted --- apps/openmw/mwworld/weather.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index db8787af7e..d98815de7b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -20,9 +20,9 @@ using namespace MWSound; #define lerp(x, y) (x * (1-factor) + y * factor) void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { - std::string upper=name; - upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); + std::string upper=name; + upper[0]=toupper(name[0]); + weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta"); weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); @@ -57,19 +57,19 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa { mRendering = rendering; //Globals - mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); - mWeatherUpdateTime = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); - mThunderSoundDelay = 0.25; - //Weather + mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); + mWeatherUpdateTime = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderSoundDelay = 0.25; + //Weather Weather clear; clear.mCloudTexture = "tx_sky_clear.dds"; setFallbackWeather(clear,"clear"); From 727a598cbe693388e5f32262aff578d3ce8992d5 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 15 Mar 2013 10:32:03 +0100 Subject: [PATCH 0715/1483] Last tabulator died --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d98815de7b..3462cfca1c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -56,7 +56,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa mTimePassed(0), mFallback(fallback) { mRendering = rendering; - //Globals + //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); From 66a2df68db176a1a40fa284318ee52ca9d32c270 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 15 Mar 2013 10:26:04 +0100 Subject: [PATCH 0716/1483] some cleanup --- apps/openmw/mwworld/fallback.cpp | 11 +++++++---- apps/openmw/mwworld/fallback.hpp | 7 ++++++- apps/openmw/mwworld/weather.cpp | 1 + apps/openmw/mwworld/weather.hpp | 4 +++- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index 24ddc3db7b..569a6b50c2 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -2,6 +2,9 @@ #include "boost/lexical_cast.hpp" namespace MWWorld { + Fallback::Fallback(const std::map& fallback):mFallbackMap(fallback) + {} + std::string Fallback::getFallbackString(const std::string& fall) const { std::map::const_iterator it; @@ -14,7 +17,7 @@ namespace MWWorld float Fallback::getFallbackFloat(const std::string& fall) const { std::string fallback=getFallbackString(fall); - if(fallback=="") + if(fallback.empty()) return 0; else return boost::lexical_cast(fallback); @@ -22,7 +25,7 @@ namespace MWWorld bool Fallback::getFallbackBool(const std::string& fall) const { std::string fallback=getFallbackString(fall); - if(fallback=="") + if(fallback.empty()) return false; else return boost::lexical_cast(fallback); @@ -30,13 +33,13 @@ namespace MWWorld Ogre::ColourValue Fallback::getFallbackColour(const std::string& fall) const { std::string sum=getFallbackString(fall); - if(sum=="") + if(sum.empty()) return Ogre::ColourValue(0,0,0); else { std::string ret[3]; unsigned int j=0; - for(unsigned int i=0;i +#include + #include + namespace MWWorld { class Fallback { const std::map mFallbackMap; public: - Fallback(const std::map fallback):mFallbackMap(fallback){}; + Fallback(const std::map& fallback); std::string getFallbackString(const std::string& fall) const; float getFallbackFloat(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 3462cfca1c..867e910fe3 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -12,6 +12,7 @@ #include "player.hpp" #include "esmstore.hpp" +#include "fallback.hpp" using namespace Ogre; using namespace MWWorld; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index ae0c2ca93b..93d908ebe5 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -3,7 +3,7 @@ #include #include -#include "fallback.hpp" + namespace MWRender { class RenderingManager; @@ -11,6 +11,8 @@ namespace MWRender namespace MWWorld { + class Fallback; + /// Defines the actual weather that results from weather setting (see below), time of day and weather transition struct WeatherResult { From 485b6c855a1ce395eda8127914588ff516f10b9f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 Mar 2013 16:44:35 +0100 Subject: [PATCH 0717/1483] Fix NPC race height not being applied --- apps/openmw/mwclass/npc.cpp | 14 ++++++++++++++ apps/openmw/mwclass/npc.hpp | 2 ++ apps/openmw/mwrender/characterpreview.cpp | 9 ++++++--- apps/openmw/mwrender/npcanimation.cpp | 5 ----- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d4e5e5cd67..2ed285a813 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -511,6 +511,20 @@ namespace MWClass x = 0; } + void Npc::adjustScale(const MWWorld::Ptr &ptr, float &scale) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + const ESM::Race* race = + MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); + + if (ref->mBase->isMale()) + scale *= race->mData.mHeight.mMale; + else + scale *= race->mData.mHeight.mFemale; + } + MWWorld::Ptr Npc::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 51e93636d3..0ca6a8d69e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -110,6 +110,8 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? + virtual void adjustScale (const MWWorld::Ptr &ptr, float &scale) const; + virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const; ///< Inform actor \a ptr that a skill use has succeeded. diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index c99e426624..843bcf007b 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -104,11 +104,14 @@ namespace MWRender mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + float scale=1.f; + MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); + mNode->setScale(Ogre::Vector3(scale)); + mNode->setVisible (false); - Ogre::Vector3 scale = mNode->getScale(); - mCamera->setPosition(mPosition * scale); - mCamera->lookAt(mLookAt * scale); + mCamera->setPosition(mPosition * mNode->getScale()); + mCamera->lookAt(mLookAt * mNode->getScale()); onSetup(); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 9da70beb45..b76a38c469 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -85,11 +85,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); - float scale = race->mData.mHeight.mMale; - if(!mNpc->isMale()) - scale = race->mData.mHeight.mFemale; - node->scale(Ogre::Vector3(scale)); - mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3a15582ba0..1bab676c3c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -885,6 +885,8 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) mPlayer->setAnimation(anim); mWater->removeEmitter (ptr); mWater->addEmitter (ptr); + // apply race height + MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f); } void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw) From c15d9201332d5e6de714442e196c40001c72037b Mon Sep 17 00:00:00 2001 From: pvdk Date: Sat, 16 Mar 2013 01:46:28 +0100 Subject: [PATCH 0718/1483] Fixed the first run dialog, makes sure Morrowind.ini is found --- apps/launcher/datafilespage.cpp | 2 +- apps/launcher/maindialog.cpp | 94 +++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 512c4b2f82..add3dea40e 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -147,7 +147,7 @@ void DataFilesPage::setupDataFiles() profilesComboBox->addItems(profiles); // Add the current profile if empty - if (profilesComboBox->findText(profile) == -1) + if (profilesComboBox->findText(profile) == -1 && !profile.isEmpty()) profilesComboBox->addItem(profile); if (profilesComboBox->findText(QString("Default")) == -1) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index e435bd391c..1a5b4d2e93 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -122,6 +122,51 @@ void MainDialog::createPages() bool MainDialog::showFirstRunDialog() { + QStringList iniPaths; + + foreach (const QString &path, mGameSettings.getDataDirs()) { + QDir dir(path); + dir.setPath(dir.canonicalPath()); // Resolve symlinks + + if (!dir.cdUp()) + continue; // Cannot move from Data Files + + if (dir.exists(QString("Morrowind.ini"))) + iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini"))); + } + + // Ask the user where the Morrowind.ini is + if (iniPaths.empty()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error detecting Morrowind configuration")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(QObject::tr("
Could not find Morrowind.ini

\ + OpenMW needs to import settings from this file.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + QString iniFile; + if (msgBox.clickedButton() == dirSelectButton) { + iniFile = QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select configuration file"), + QDir::currentPath(), + QString(tr("Morrowind configuration file (*.ini)"))); + } + + if (iniFile.isEmpty()) + return false; // Cancel was clicked; + + QFileInfo info(iniFile); + iniPaths.clear(); + iniPaths.append(info.absoluteFilePath()); + } + CheckableMessageBox msgBox(this); msgBox.setWindowTitle(tr("Morrowind installation detected")); @@ -129,7 +174,6 @@ bool MainDialog::showFirstRunDialog() int size = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize); msgBox.setIconPixmap(icon.pixmap(size, size)); - QAbstractButton *importerButton = msgBox.addButton(tr("Import"), QDialogButtonBox::AcceptRole); // ActionRole doesn't work?! QAbstractButton *skipButton = @@ -138,54 +182,27 @@ bool MainDialog::showFirstRunDialog() Q_UNUSED(skipButton); // Surpress compiler unused warning msgBox.setStandardButtons(QDialogButtonBox::NoButton); - - msgBox.setText(tr("
An existing Morrowind installation was detected

\ + msgBox.setText(tr("
An existing Morrowind configuration was detected

\ Would you like to import settings from Morrowind.ini?
")); - msgBox.setCheckBoxText(tr("Include selected masters and plugins (creates a new profile)")); msgBox.exec(); if (msgBox.clickedButton() == importerButton) { - QStringList iniPaths; - - foreach (const QString &path, mGameSettings.getDataDirs()) { - QDir dir(path); - dir.setPath(dir.canonicalPath()); // Resolve symlinks - - if (!dir.cdUp()) - continue; // Cannot move from Data Files - - if (dir.exists(QString("Morrowind.ini"))) - iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini"))); - } - - if (iniPaths.isEmpty()) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error reading Morrowind configuration file")); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not find Morrowind.ini

\ - The problem may be due to an incomplete installation of Morrowind.
\ - Reinstalling Morrowind may resolve the problem.")); - msgBox.exec(); - return false; - } - if (iniPaths.count() > 1) { // Multiple Morrowind.ini files found bool ok; - QString path = QInputDialog::getItem(this, tr("Multiple configurations found"), + QString path = QInputDialog::getItem(this, tr("Multiple configurations found"), tr("
There are multiple Morrowind.ini files found.

\ Please select the one you wish to import from:"), iniPaths, 0, false, &ok); - if (ok && !path.isEmpty()) { - iniPaths.clear(); - iniPaths.append(path); - } else { - // Cancel was clicked TODO: should we abort here? - return false; - } + if (ok && !path.isEmpty()) { + iniPaths.clear(); + iniPaths.append(path); + } else { + // Cancel was clicked + return false; + } } // Create the file if it doesn't already exist, else the importer will fail @@ -212,7 +229,6 @@ bool MainDialog::showFirstRunDialog() // Construct the arguments to run the importer QStringList arguments; - if (msgBox.isChecked()) arguments.append(QString("--game-files")); @@ -232,7 +248,7 @@ bool MainDialog::showFirstRunDialog() // Add a new profile if (msgBox.isChecked()) { - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), QString("Imported")); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), QString("Imported")); mLauncherSettings.remove(QString("Profiles/Imported/master")); mLauncherSettings.remove(QString("Profiles/Imported/plugin")); From 8d706f81830fd051f170d8c492d1da6ac3b6b070 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 16 Mar 2013 10:36:35 +0100 Subject: [PATCH 0719/1483] Include the ini importer in windows packages --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 574ff555b1..e1b8e32e5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,6 +384,7 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/Daedric Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" + "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe" "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") From c9658031d25ea373a1177a81c4a5bb1d721a37b4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 16 Mar 2013 11:38:38 +0100 Subject: [PATCH 0720/1483] changelog update --- readme.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/readme.txt b/readme.txt index bc3d63c789..8edb0c4b31 100644 --- a/readme.txt +++ b/readme.txt @@ -103,7 +103,6 @@ Bug #387: Always use detailed shape for physics raycasts Bug #420: Potion/ingredient effects do not stack Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips Bug #434/Bug #605: Object movement between cells not properly implemented -Bug #455: Animation doesn't move creature's bounding box Bug #502: Duplicate player collision model at origin Bug #509: Dialogue topic list shifts inappropriately Bug #513: Sliding stairs From d1860f2d6c2c455b605180576e22efdbb759209d Mon Sep 17 00:00:00 2001 From: pvdk Date: Sat, 16 Mar 2013 13:40:29 +0100 Subject: [PATCH 0721/1483] Removed color information from Direct3D resolutions --- apps/launcher/graphicspage.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 19de88b67b..4fde1aab05 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -268,16 +268,17 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) int height = resolutionRe.cap(2).toInt(); QString aspect = getAspect(width, height); + QString cleanRes = QString::number(width) + QString(" x ") + QString::number(height); if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { - resolution.append(tr("\t(Wide ") + aspect + ")"); + cleanRes.append(tr("\t(Wide ") + aspect + ")"); } else if (aspect == QLatin1String("4:3")) { - resolution.append(tr("\t(Standard 4:3)")); + cleanRes.append(tr("\t(Standard 4:3)")); } // do not add duplicate resolutions - if (!result.contains(resolution)) - result.append(resolution); + if (!result.contains(cleanRes)) + result.append(cleanRes); } } } From 75be47400573fda26ea5cf089960842861b6341e Mon Sep 17 00:00:00 2001 From: pvdk Date: Sat, 16 Mar 2013 13:45:23 +0100 Subject: [PATCH 0722/1483] Use the resolution QRegExp cap() instead of converting ints back and forth --- apps/launcher/graphicspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 4fde1aab05..700ba3db9c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -268,7 +268,7 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) int height = resolutionRe.cap(2).toInt(); QString aspect = getAspect(width, height); - QString cleanRes = QString::number(width) + QString(" x ") + QString::number(height); + QString cleanRes = resolutionRe.cap(1) + QString(" x ") + resolutionRe.cap(2); if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { cleanRes.append(tr("\t(Wide ") + aspect + ")"); From 83932ebfe8ad58b40b223d7b404c0fef037eecb1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 14:36:37 +0100 Subject: [PATCH 0723/1483] HLSL shader fix --- files/materials/watersim_heightmap.shader | 9 ++++++++ .../materials/watersim_heighttonormal.shader | 21 +++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader index 50d375efe4..ec8ae4174a 100644 --- a/files/materials/watersim_heightmap.shader +++ b/files/materials/watersim_heightmap.shader @@ -14,12 +14,21 @@ SH_START_PROGRAM { +#if !SH_HLSL const float3 offset[4] = float3[4]( float3(-1.0, 0.0, 0.25), float3( 1.0, 0.0, 0.25), float3( 0.0,-1.0, 0.25), float3( 0.0, 1.0, 0.25) ); +#else + const float3 offset[4] = { + float3(-1.0, 0.0, 0.25), + float3( 1.0, 0.0, 0.25), + float3( 0.0,-1.0, 0.25), + float3( 0.0, 1.0, 0.25) + }; +#endif float fHeightPrev = DecodeHeightmap(heightPrevSampler, UV.xy + previousFrameOffset.xy + currentFrameOffset.xy); diff --git a/files/materials/watersim_heighttonormal.shader b/files/materials/watersim_heighttonormal.shader index 5402b6bb5e..eaa4af4983 100644 --- a/files/materials/watersim_heighttonormal.shader +++ b/files/materials/watersim_heighttonormal.shader @@ -8,12 +8,21 @@ SH_START_PROGRAM { - float2 offset[4] = float2[4] ( - vec2(-1.0, 0.0), - vec2( 1.0, 0.0), - vec2( 0.0,-1.0), - vec2( 0.0, 1.0) - ); +#if !SH_HLSL + float2 offset[4] = float2[4] ( + float2(-1.0, 0.0), + float2( 1.0, 0.0), + float2( 0.0,-1.0), + float2( 0.0, 1.0) + ); +#else + float2 offset[4] = { + float2(-1.0, 0.0), + float2( 1.0, 0.0), + float2( 0.0,-1.0), + float2( 0.0, 1.0) + }; +#endif float fHeightL = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[0]*rippleTextureSize.xy); float fHeightR = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[1]*rippleTextureSize.xy); From c0b0227e8a494ea27cdc0c82df20ff4929e015d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 19:00:14 +0100 Subject: [PATCH 0724/1483] enchanting --- apps/openmw/mwclass/armor.cpp | 8 ++ apps/openmw/mwclass/armor.hpp | 2 + apps/openmw/mwclass/clothing.cpp | 8 ++ apps/openmw/mwclass/clothing.hpp | 2 + apps/openmw/mwclass/weapon.cpp | 8 ++ apps/openmw/mwclass/weapon.hpp | 2 + apps/openmw/mwgui/container.cpp | 70 ++++++++--- apps/openmw/mwgui/container.hpp | 23 ++-- apps/openmw/mwgui/dialogue.cpp | 4 +- apps/openmw/mwgui/enchantingdialog.cpp | 130 ++++++++++++++++++++ apps/openmw/mwgui/enchantingdialog.hpp | 31 +++++ apps/openmw/mwgui/itemselection.cpp | 2 +- apps/openmw/mwgui/itemselection.hpp | 2 +- apps/openmw/mwworld/class.cpp | 5 + apps/openmw/mwworld/class.hpp | 3 + files/mygui/openmw_chargen_race.layout | 6 +- files/mygui/openmw_enchanting_dialog.layout | 15 ++- 17 files changed, 281 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index fdf211c28a..130c0515d0 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -290,4 +290,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mArmors.insert(*ref), &cell); } + + short Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mEnchant; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 51c0ea21c9..ff45411ed2 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -70,6 +70,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index dfced6daa8..f5f71a7767 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,4 +238,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mClothes.insert(*ref), &cell); } + + short Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mEnchant; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index f7801848f6..f01c78afce 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -64,6 +64,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 475c08ccbf..0f6e86811e 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -378,4 +378,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mWeapons.insert(*ref), &cell); } + + short Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mEnchant; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 06cf88c5f2..bf34172516 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -70,6 +70,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2b80003127..1b4a982765 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -68,6 +68,16 @@ namespace return compareType(left.getTypeName(), right.getTypeName()); } } + + bool isChargedSoulstone (MWWorld::Ptr ptr) + { + if (ptr.getTypeName() != typeid(ESM::Miscellaneous).name()) + return false; + MWWorld::LiveCellRef *ref = + ptr.get(); + + return (ref->mRef.mSoul != ""); + } } @@ -345,7 +355,7 @@ void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0)); } -void ContainerBase::setFilter(ContainerBase::Filter filter) +void ContainerBase::setFilter(int filter) { mFilter = filter; drawItems(); @@ -369,29 +379,34 @@ void ContainerBase::drawItems() int maxHeight = mItemView->getSize().height - 58; bool onlyMagic = false; + bool noMagic = false; int categories = 0; - if (mFilter == Filter_All) - categories = MWWorld::ContainerStore::Type_All; - else if (mFilter == Filter_Weapon) - categories = MWWorld::ContainerStore::Type_Weapon; - else if (mFilter == Filter_Apparel) - categories = MWWorld::ContainerStore::Type_Clothing + MWWorld::ContainerStore::Type_Armor; - else if (mFilter == Filter_Magic) + if (mFilter & Filter_All) + categories |= MWWorld::ContainerStore::Type_All; + if (mFilter & Filter_Weapon) + categories |= MWWorld::ContainerStore::Type_Weapon; + if (mFilter & Filter_Apparel) + categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor; + if (mFilter & Filter_Magic) { - categories = MWWorld::ContainerStore::Type_Clothing + MWWorld::ContainerStore::Type_Armor - + MWWorld::ContainerStore::Type_Weapon + MWWorld::ContainerStore::Type_Book - + MWWorld::ContainerStore::Type_Potion; + categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor + | MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Book + | MWWorld::ContainerStore::Type_Potion; onlyMagic = true; } - else if (mFilter == Filter_Misc) + if (mFilter & Filter_Misc) { - categories = MWWorld::ContainerStore::Type_Miscellaneous + MWWorld::ContainerStore::Type_Book - + MWWorld::ContainerStore::Type_Ingredient + MWWorld::ContainerStore::Type_Repair - + MWWorld::ContainerStore::Type_Lockpick + MWWorld::ContainerStore::Type_Light - + MWWorld::ContainerStore::Type_Apparatus + MWWorld::ContainerStore::Type_Probe; + categories |= MWWorld::ContainerStore::Type_Miscellaneous | MWWorld::ContainerStore::Type_Book + | MWWorld::ContainerStore::Type_Ingredient | MWWorld::ContainerStore::Type_Repair + | MWWorld::ContainerStore::Type_Lockpick | MWWorld::ContainerStore::Type_Light + | MWWorld::ContainerStore::Type_Apparatus | MWWorld::ContainerStore::Type_Probe; } - else if (mFilter == Filter_Ingredients) - categories = MWWorld::ContainerStore::Type_Ingredient; + if (mFilter & Filter_Ingredients) + categories |= MWWorld::ContainerStore::Type_Ingredient; + if (mFilter & Filter_ChargedSoulstones) + categories |= MWWorld::ContainerStore::Type_Miscellaneous; + if (mFilter & Filter_NoMagic) + noMagic = true; /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them @@ -466,12 +481,29 @@ void ContainerBase::drawItems() { const MWWorld::Ptr* iter = &((*it).first); + + if (onlyMagic + && it->second != ItemState_Barter + && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" + && iter->getTypeName() != typeid(ESM::Potion).name()) + continue; + + if (noMagic + && it->second != ItemState_Barter + && (MWWorld::Class::get(*iter).getEnchantment(*iter) != "" + || iter->getTypeName() == typeid(ESM::Potion).name())) + continue; + + if ( (mFilter & Filter_ChargedSoulstones) + && !isChargedSoulstone(*iter)) + continue; + int displayCount = iter->getRefData().getCount(); if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) { displayCount -= mDragAndDrop->mDraggedCount; } - if(displayCount > 0 && !(onlyMagic && it->second != ItemState_Barter && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) + if(displayCount > 0) { std::string path = std::string("icons\\"); path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 3c8127b26c..49e60aa251 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -48,16 +48,17 @@ namespace MWGui ContainerBase(DragAndDrop* dragAndDrop); virtual ~ContainerBase(); - enum Filter - { - Filter_All = 0x01, - Filter_Weapon = 0x02, - Filter_Apparel = 0x03, - Filter_Magic = 0x04, - Filter_Misc = 0x05, + // basic types (inclusive) + static const int Filter_All = (1<<0); + static const int Filter_Weapon = (1<<1); + static const int Filter_Apparel = (1<<2); + static const int Filter_Ingredients = (1<<3); + static const int Filter_Misc = (1<<4); - Filter_Ingredients = 0x06 - }; + // special filtering (exclusive) + static const int Filter_Magic = (1<<5); + static const int Filter_NoMagic = (1<<6); + static const int Filter_ChargedSoulstones = (1<<7); enum ItemState { @@ -78,7 +79,7 @@ namespace MWGui MWWorld::ContainerStore& getBoughtItems() { return mBoughtItems; } void openContainer(MWWorld::Ptr container); - void setFilter(Filter filter); ///< set category filter + void setFilter(int filter); ///< set category filter void drawItems(); protected: @@ -92,7 +93,7 @@ namespace MWGui DragAndDrop* mDragAndDrop; - Filter mFilter; + int mFilter; // bought items are put in a separate ContainerStore so that they don't stack with other (not bought) items. MWWorld::ContainerStore mBoughtItems; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index cdcbfc4d18..d4125a05f0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -316,8 +316,8 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_CreateSpells) mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); -// if (mServices & Service_Enchant) -// mTopicsList->addItem(gmst.find("sEnchanting")->getString()); + if (mServices & Service_Enchant) + mTopicsList->addItem(gmst.find("sEnchanting")->getString()); if (mServices & Service_Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 3bd67ade63..673739cbf3 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -1,5 +1,13 @@ #include "enchantingdialog.hpp" +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/player.hpp" + +#include "itemselection.hpp" +#include "container.hpp" namespace MWGui { @@ -8,19 +16,45 @@ namespace MWGui EnchantingDialog::EnchantingDialog(MWBase::WindowManager &parWindowManager) : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) , EffectEditorBase(parWindowManager) + , mItemSelectionDialog(NULL) + , mCurrentEnchantmentPoints(0) { getWidget(mCancelButton, "CancelButton"); getWidget(mAvailableEffectsList, "AvailableEffects"); getWidget(mUsedEffectsView, "UsedEffects"); + getWidget(mItemBox, "ItemBox"); + getWidget(mSoulBox, "SoulBox"); + getWidget(mEnchantmentPoints, "Enchantment"); + getWidget(mCastCost, "CastCost"); + getWidget(mCharge, "Charge"); + getWidget(mTypeButton, "TypeButton"); + getWidget(mBuyButton, "BuyButton"); + getWidget(mPrice, "PriceLabel"); setWidgets(mAvailableEffectsList, mUsedEffectsView); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onCancelButtonClicked); + mItemBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectItem); + mSoulBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectSoul); + } + + EnchantingDialog::~EnchantingDialog() + { + delete mItemSelectionDialog; } void EnchantingDialog::open() { center(); + onRemoveItem(NULL); + onRemoveSoul(NULL); + } + + void EnchantingDialog::updateLabels() + { + mEnchantmentPoints->setCaption(boost::lexical_cast(mCurrentEnchantmentPoints) + + " / " + (mItem.isEmpty() ? "0" : boost::lexical_cast( + MWWorld::Class::get(mItem).getEnchantmentPoints(mItem)))); } void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) @@ -40,4 +74,100 @@ namespace MWGui { mWindowManager.removeGuiMode (GM_Enchanting); } + + void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) + { + delete mItemSelectionDialog; + mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}", + ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, mWindowManager); + mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); + mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); + mItemSelectionDialog->setVisible(true); + mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + mItemSelectionDialog->drawItems (); + } + + void EnchantingDialog::onItemSelected(MWWorld::Ptr item) + { + mItemSelectionDialog->setVisible(false); + + while (mItemBox->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mItemBox->getChildAt(0)); + + MyGUI::ImageBox* image = mItemBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(item).getInventoryIcon(item); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture (path); + image->setUserString ("ToolTipType", "ItemPtr"); + image->setUserData(item); + image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem); + + mItem = item; + updateLabels(); + } + + void EnchantingDialog::onRemoveItem(MyGUI::Widget *sender) + { + while (mItemBox->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mItemBox->getChildAt(0)); + mItem = MWWorld::Ptr(); + updateLabels(); + } + + void EnchantingDialog::onItemCancel() + { + mItemSelectionDialog->setVisible(false); + } + + void EnchantingDialog::onSoulSelected(MWWorld::Ptr item) + { + mItemSelectionDialog->setVisible(false); + + while (mSoulBox->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); + + MyGUI::ImageBox* image = mSoulBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(item).getInventoryIcon(item); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture (path); + image->setUserString ("ToolTipType", "ItemPtr"); + image->setUserData(item); + image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); + + mSoul = item; + updateLabels(); + } + + void EnchantingDialog::onRemoveSoul(MyGUI::Widget *sender) + { + while (mSoulBox->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); + mSoul = MWWorld::Ptr(); + updateLabels(); + } + + void EnchantingDialog::onSoulCancel() + { + mItemSelectionDialog->setVisible(false); + } + + void EnchantingDialog::onSelectSoul(MyGUI::Widget *sender) + { + delete mItemSelectionDialog; + mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}", + ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, mWindowManager); + mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); + mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); + mItemSelectionDialog->setVisible(true); + mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + mItemSelectionDialog->drawItems (); + + //mWindowManager.messageBox("#{sInventorySelectNoSoul}"); + } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 0415c9d8df..bcebb799df 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -10,10 +10,13 @@ namespace MWGui { + class ItemSelectionDialog; + class EnchantingDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { public: EnchantingDialog(MWBase::WindowManager& parWindowManager); + virtual ~EnchantingDialog(); virtual void open(); void startEnchanting(MWWorld::Ptr actor); @@ -22,8 +25,36 @@ namespace MWGui virtual void onReferenceUnavailable(); void onCancelButtonClicked(MyGUI::Widget* sender); + void onSelectItem (MyGUI::Widget* sender); + void onSelectSoul (MyGUI::Widget* sender); + void onRemoveItem (MyGUI::Widget* sender); + void onRemoveSoul (MyGUI::Widget* sender); + + void onItemSelected(MWWorld::Ptr item); + void onItemCancel(); + void onSoulSelected(MWWorld::Ptr item); + void onSoulCancel(); + + void updateLabels(); + + ItemSelectionDialog* mItemSelectionDialog; MyGUI::Button* mCancelButton; + MyGUI::ImageBox* mItemBox; + MyGUI::ImageBox* mSoulBox; + + MyGUI::Button* mTypeButton; + MyGUI::Button* mBuyButton; + + MyGUI::TextBox* mEnchantmentPoints; + MyGUI::TextBox* mCastCost; + MyGUI::TextBox* mCharge; + MyGUI::TextBox* mPrice; + + MWWorld::Ptr mItem; + MWWorld::Ptr mSoul; + + float mCurrentEnchantmentPoints; }; } diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 14b1cf8ee5..4b8adcef4f 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -3,7 +3,7 @@ namespace MWGui { - ItemSelectionDialog::ItemSelectionDialog(const std::string &label, ContainerBase::Filter filter, MWBase::WindowManager& parWindowManager) + ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter, MWBase::WindowManager& parWindowManager) : ContainerBase(NULL) , WindowModal("openmw_itemselection_dialog.layout", parWindowManager) { diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index cab125f1f8..733daa91ae 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -8,7 +8,7 @@ namespace MWGui class ItemSelectionDialog : public ContainerBase, public WindowModal { public: - ItemSelectionDialog(const std::string& label, ContainerBase::Filter filter, MWBase::WindowManager& parWindowManager); + ItemSelectionDialog(const std::string& label, int filter, MWBase::WindowManager& parWindowManager); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 71b24b65dc..cc20aeda75 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -127,6 +127,11 @@ namespace MWWorld return 0; } + short Class::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error ("class does not support enchanting"); + } + MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const { throw std::runtime_error ("movement settings not supported by class"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1a6a16ca07..77c29fe489 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -222,6 +222,9 @@ namespace MWWorld ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + ///< @return the number of enchantment points available for possible enchanting + virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const; virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const; diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 4ef8da0f3f..c0b04618ed 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index a19c569256..2549fd26f9 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -26,14 +26,18 @@ - + + + - + + + @@ -85,7 +89,11 @@ - + + + + + @@ -97,6 +105,7 @@ + From cebcbe11f8f8fca480b6271b568761c7f03e8036 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 20:32:21 +0100 Subject: [PATCH 0725/1483] Implemented service refusal --- apps/openmw/mwbase/dialoguemanager.hpp | 2 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 31 ++++++++++ apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 + apps/openmw/mwdialogue/filter.cpp | 13 ++-- apps/openmw/mwdialogue/filter.hpp | 6 +- apps/openmw/mwgui/dialogue.cpp | 60 ++++++++++--------- 6 files changed, 76 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index a205e78db7..db86385d4e 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -41,6 +41,8 @@ namespace MWBase virtual void goodbyeSelected() = 0; virtual void questionAnswered (const std::string& answer) = 0; + virtual bool checkServiceRefused () = 0; + virtual void persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; virtual void applyTemporaryDispositionChange (int delta) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 35f0c94937..62ee09bdba 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -518,6 +518,37 @@ namespace MWDialogue mTemporaryDispositionChange += delta; } + bool DialogueManager::checkServiceRefused() + { + Filter filter (mActor, mChoice, mTalkedTo); + + const MWWorld::Store &dialogues = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Dialogue& dialogue = *dialogues.find ("Service Refusal"); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + + std::vector infos = filter.list (dialogue, false, false, true); + if (!infos.empty()) + { + const ESM::DialInfo* info = infos[0]; + + parseText (info->mResponse); + + const MWWorld::Store& gmsts = + MWBase::Environment::get().getWorld()->getStore().get(); + + win->addTitle (gmsts.find ("sServiceRefusal")->getString()); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + + executeScript (info->mResultScript); + return true; + } + return false; + } + std::vector ParseHyperText(const std::string& text) { std::vector result; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 1ca2ae5ebc..ad537b0ad4 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -65,6 +65,8 @@ namespace MWDialogue virtual MWWorld::Ptr getActor() const; ///< Return the actor the player is currently talking to. + virtual bool checkServiceRefused (); + //calbacks for the GUI virtual void keywordSelected (const std::string& keyword); virtual void goodbyeSelected(); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 10740794ea..906e30c768 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -121,7 +121,7 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const return true; } -bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const +bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert) const { bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); @@ -129,8 +129,9 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const return true; int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); - - return actorDisposition >= info.mData.mDisposition; + // For service refusal, the disposition check is inverted. However, a value of 0 still means "always succeed". + return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition) + : (actorDisposition >= info.mData.mDisposition); } bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const @@ -570,7 +571,7 @@ const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, } std::vector MWDialogue::Filter::list (const ESM::Dialogue& dialogue, - bool fallbackToInfoRefusal, bool searchAll) const + bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition) const { std::vector infos; @@ -582,7 +583,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { - if (testDisposition (*iter)) { + if (testDisposition (*iter, invertDisposition)) { infos.push_back(&*iter); if (!searchAll) break; @@ -604,7 +605,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) - if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter, invertDisposition)) { infos.push_back(&*iter); if (!searchAll) break; diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 069bf6353d..5c6d092ad9 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -30,8 +30,8 @@ namespace MWDialogue bool testSelectStructs (const ESM::DialInfo& info) const; ///< Are all select structs matching? - bool testDisposition (const ESM::DialInfo& info) const; - ///< Is the actor disposition toward the player high enough? + bool testDisposition (const ESM::DialInfo& info, bool invert=false) const; + ///< Is the actor disposition toward the player high enough (or low enough, if \a invert is true)? bool testSelectStruct (const SelectWrapper& select) const; @@ -54,7 +54,7 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); std::vector list (const ESM::Dialogue& dialogue, - bool fallbackToInfoRefusal, bool searchAll) const; + bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition=false) const; const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index cdcbfc4d18..c500cd1747 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -241,40 +241,42 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (topic == gmst.find("sBarter")->getString()) - { - /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? - mWindowManager.pushGuiMode(GM_Barter); - mWindowManager.getTradeWindow()->startTrade(mPtr); - } if (topic == gmst.find("sPersuasion")->getString()) { mPersuasionDialog.setVisible(true); } - else if (topic == gmst.find("sSpells")->getString()) + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { - mWindowManager.pushGuiMode(GM_SpellBuying); - mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); - } - else if (topic == gmst.find("sTravel")->getString()) - { - mWindowManager.pushGuiMode(GM_Travel); - mWindowManager.getTravelWindow()->startTravel(mPtr); - } - else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - mWindowManager.pushGuiMode(GM_SpellCreation); - mWindowManager.startSpellMaking (mPtr); - } - else if (topic == gmst.find("sEnchanting")->getString()) - { - mWindowManager.pushGuiMode(GM_Enchanting); - mWindowManager.startEnchanting (mPtr); - } - else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - mWindowManager.pushGuiMode(GM_Training); - mWindowManager.startTraining (mPtr); + if (topic == gmst.find("sBarter")->getString()) + { + mWindowManager.pushGuiMode(GM_Barter); + mWindowManager.getTradeWindow()->startTrade(mPtr); + } + else if (topic == gmst.find("sSpells")->getString()) + { + mWindowManager.pushGuiMode(GM_SpellBuying); + mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); + } + else if (topic == gmst.find("sTravel")->getString()) + { + mWindowManager.pushGuiMode(GM_Travel); + mWindowManager.getTravelWindow()->startTravel(mPtr); + } + else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_SpellCreation); + mWindowManager.startSpellMaking (mPtr); + } + else if (topic == gmst.find("sEnchanting")->getString()) + { + mWindowManager.pushGuiMode(GM_Enchanting); + mWindowManager.startEnchanting (mPtr); + } + else if (topic == gmst.find("sServiceTrainingTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_Training); + mWindowManager.startTraining (mPtr); + } } } } From e8b08326dc47d39faf4da2119ee2681818ed2db0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 20:52:05 +0100 Subject: [PATCH 0726/1483] Corrected Id, Race, Class, Faction and Cell select functions to do the exact opposite as before. That is how they are displayed in the CS, anyway. --- apps/openmw/mwdialogue/filter.cpp | 20 ++++++++++---------- apps/openmw/mwdialogue/selectwrapper.cpp | 14 +++++++------- apps/openmw/mwdialogue/selectwrapper.hpp | 10 +++++----- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 906e30c768..d3405b2b26 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -413,25 +413,25 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return false; - case SelectWrapper::Function_Id: + case SelectWrapper::Function_NotId: - return select.getName()==Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor)); + return select.getName()!=Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor)); - case SelectWrapper::Function_Faction: + case SelectWrapper::Function_NotFaction: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mFaction)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mFaction)!=select.getName(); - case SelectWrapper::Function_Class: + case SelectWrapper::Function_NotClass: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mClass)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mClass)!=select.getName(); - case SelectWrapper::Function_Race: + case SelectWrapper::Function_NotRace: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mRace)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mRace)!=select.getName(); - case SelectWrapper::Function_Cell: + case SelectWrapper::Function_NotCell: - return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)!=select.getName(); case SelectWrapper::Function_SameGender: diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 9d705f6bec..77930ae423 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -112,11 +112,11 @@ MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() con case '4': return Function_Journal; case '5': return Function_Item; case '6': return Function_Dead; - case '7': return Function_Id; - case '8': return Function_Faction; - case '9': return Function_Class; - case 'A': return Function_Race; - case 'B': return Function_Cell; + case '7': return Function_NotId; + case '8': return Function_NotFaction; + case '9': return Function_NotClass; + case 'A': return Function_NotRace; + case 'B': return Function_NotCell; case 'C': return Function_Local; } @@ -219,7 +219,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function booleanFunctions[] = { Function_False, - Function_Id, Function_Faction, Function_Class, Function_Race, Function_Cell, + Function_NotId, Function_NotFaction, Function_NotClass, Function_NotRace, Function_NotCell, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus, Function_PcExpelled, @@ -259,7 +259,7 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const { static const Function functions[] = { - Function_Faction, SelectWrapper::Function_Class, SelectWrapper::Function_Race, + Function_NotFaction, SelectWrapper::Function_NotClass, SelectWrapper::Function_NotRace, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcSkill, Function_PcExpelled, diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index b77ed7985a..c27339afa0 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -17,11 +17,11 @@ namespace MWDialogue Function_Journal, Function_Item, Function_Dead, - Function_Id, - Function_Faction, - Function_Class, - Function_Race, - Function_Cell, + Function_NotId, + Function_NotFaction, + Function_NotClass, + Function_NotRace, + Function_NotCell, Function_Local, Function_Global, Function_SameGender, Function_SameRace, Function_SameFaction, From 1666bc77407deb0a89657a8e73d6f7dce93417e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 22:53:33 +0100 Subject: [PATCH 0727/1483] Armor rating --- apps/openmw/mwbase/mechanicsmanager.hpp | 5 +- apps/openmw/mwgui/inventorywindow.cpp | 5 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 49 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 ++ files/mygui/openmw_inventory_window.layout | 1 - 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index b8733259ff..6cb7c69188 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -82,7 +82,10 @@ namespace MWBase virtual int getDerivedDisposition(const MWWorld::Ptr& ptr) = 0; ///< Calculate the diposition of an NPC toward the player. - + + virtual float getArmorRating (const MWWorld::Ptr& ptr) = 0; + ///< Calculate the combined armor rating of an NPC. + virtual int countDeaths (const std::string& id) const = 0; ///< Return the number of deaths for actors with the given ID. diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ab7615c0ef..2caed79728 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -13,6 +13,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -50,6 +51,7 @@ namespace MWGui getWidget(mFilterMisc, "MiscButton"); getWidget(mLeftPane, "LeftPane"); getWidget(mRightPane, "RightPane"); + getWidget(mArmorRating, "ArmorRating"); mAvatar->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); @@ -288,6 +290,9 @@ namespace MWGui mPreview.update (size.width, size.height); mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); mAvatarImage->setImageTexture("CharacterPreview"); + + mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + + boost::lexical_cast(static_cast(MWBase::Environment::get().getMechanicsManager()->getArmorRating(mPtr)))); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c9e4c77eaf..c19b84cd80 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,7 @@ #include "mechanicsmanagerimp.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -668,4 +669,52 @@ namespace MWMechanics mActors.skipAnimation(ptr); } + float MechanicsManager::getArmorRating(const MWWorld::Ptr &ptr) + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + int ratings[MWWorld::InventoryStore::Slots]; + + int iBaseArmorSkill = gmst.find("iBaseArmorSkill")->getInt(); + float fUnarmoredBase1 = gmst.find("fUnarmoredBase1")->getFloat(); + float fUnarmoredBase2 = gmst.find("fUnarmoredBase2")->getFloat(); + int unarmoredSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(ESM::Skill::Unarmored).getModified(); + + for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(i); + if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) + { + // unarmored + ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + } + else + { + MWWorld::LiveCellRef *ref = + it->get(); + + int armorSkillType = MWWorld::Class::get(*it).getEquipmentSkill(*it); + int armorSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(armorSkillType).getModified(); + + if (ref->mBase->mData.mWeight == 0) + ratings[i] = ref->mBase->mData.mArmor; + else + ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + } + + float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(3).mMagnitude; + + return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 + + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] + + ratings[MWWorld::InventoryStore::Slot_Greaves] + ratings[MWWorld::InventoryStore::Slot_Boots] + + ratings[MWWorld::InventoryStore::Slot_LeftPauldron] + ratings[MWWorld::InventoryStore::Slot_RightPauldron] + ) * 0.1 + + (ratings[MWWorld::InventoryStore::Slot_LeftGauntlet] + MWWorld::InventoryStore::Slot_RightGauntlet) + * 0.05 + + shield; + } + } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5ad8705719..2e09c5f8e5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,6 +88,9 @@ namespace MWMechanics virtual int getDerivedDisposition(const MWWorld::Ptr& ptr); ///< Calculate the diposition of an NPC toward the player. + virtual float getArmorRating (const MWWorld::Ptr& ptr); + ///< Calculate the combined armor rating of an NPC. + virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 88cc5638d3..41bd40f923 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -17,7 +17,6 @@ - From dd57eabc3ef9475f2c9b7e2aadba5da8d519cd33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 23:28:26 +0100 Subject: [PATCH 0728/1483] Better use an enum for magic effect IDs --- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwdialogue/filter.cpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 9 +- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- components/esm/loadmgef.hpp | 152 ++++++++++++++++++ 8 files changed, 164 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 19f327dcbb..1b6212a238 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -203,9 +203,9 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (8)).mMagnitude; // feather + weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).mMagnitude; - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (7)).mMagnitude; // burden + weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).mMagnitude; if (weight<0) weight = 0; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2ed285a813..d931b9e2ea 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -471,9 +471,9 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (8)).mMagnitude; // feather + weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).mMagnitude; - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (7)).mMagnitude; // burden + weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).mMagnitude; if (weight<0) weight = 0; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index d3405b2b26..7b5f354a23 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -459,7 +459,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_PcCorprus: return MWWorld::Class::get (player).getCreatureStats (player). - getMagicEffects().get (132).mMagnitude!=0; + getMagicEffects().get (ESM::MagicEffect::Corprus).mMagnitude!=0; case SelectWrapper::Function_PcExpelled: { diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 794a9ab55f..6e914a669b 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -159,7 +159,7 @@ namespace MWGui float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; - bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(136)).mMagnitude > 0); + bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0); float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9632bdf769..efbda83ee4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -71,7 +71,7 @@ namespace MWMechanics int endurance = creatureStats.getAttribute(5).getBase(); double magickaFactor = - creatureStats.getMagicEffects().get (EffectKey (84)).mMagnitude * 0.1 + 0.5; + creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude * 0.1 + 0.5; DynamicStat health = creatureStats.getHealth(); health.setBase (static_cast (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ()); @@ -92,8 +92,7 @@ namespace MWMechanics if (duration == 3600) { - // stunted magicka - bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(136)).mMagnitude > 0; + bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); @@ -140,9 +139,9 @@ namespace MWMechanics for (int i=0; i<8; ++i) { int modifier = - creatureStats.getMagicEffects().get (EffectKey (79, i)).mMagnitude; + creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyAttribute, i)).mMagnitude; - modifier -= creatureStats.getMagicEffects().get (EffectKey (17, i)).mMagnitude; + modifier -= creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::DrainAttribute, i)).mMagnitude; creatureStats.getAttribute(i).setModifier (modifier); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c19b84cd80..ac470fbbac 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -705,7 +705,7 @@ namespace MWMechanics } } - float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(3).mMagnitude; + float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Shield).mMagnitude; return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5a23aae972..a8b4135187 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1259,7 +1259,7 @@ namespace MWWorld World::isFlying(const MWWorld::Ptr &ptr) const { const MWWorld::Class &cls = MWWorld::Class::get(ptr); - if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) + if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Levitate)).mMagnitude > 0) return true; return false; } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 93c59f9cbe..7efc17aec5 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -66,6 +66,158 @@ struct MagicEffect void load(ESMReader &esm); void save(ESMWriter &esm); + + + enum Effects + { + WaterBreathing = 0, + SwiftSwim = 1, + WaterWalking = 2, + Shield = 3, + FireShield = 4, + LightningShield = 5, + FrostShield = 6, + Burden = 7, + Feather = 8, + Jump = 9, + Levitate = 10, + SlowFall = 11, + Lock = 12, + Open = 13, + FireDamage = 14, + ShockDamage = 15, + FrostDamage = 16, + DrainAttribute = 17, + DrainHealth = 18, + DrainMagicka = 19, + DrainFatigue = 20, + DrainSkill = 21, + DamageAttribute = 22, + DamageHealth = 23, + DamageMagicka = 24, + DamageFatigue = 25, + DamageSkill = 26, + Poison = 27, + WeaknessToFire = 28, + WeaknessToFrost = 29, + WeaknessToShock = 30, + WeaknessToMagicka = 31, + WeaknessToCommonDisease = 32, + WeaknessToBlightDisease = 33, + WeaknessToCorprusDisease = 34, + WeaknessToPoison = 35, + WeaknessToNormalWeapons = 36, + DisintegrateWeapon = 37, + DisintegrateArmor = 38, + Invisibility = 39, + Chameleon = 40, + Light = 41, + Sanctuary = 42, + NightEye = 43, + Charm = 44, + Paralyze = 45, + Silence = 46, + Blind = 47, + Sound = 48, + CalmHumanoid = 49, + CalmCreature = 50, + FrenzyHumanoid = 51, + FrenzyCreature = 52, + DemoralizeHumanoid = 53, + DemoralizeCreature = 54, + RallyHumanoid = 55, + RallyCreature = 56, + Dispel = 57, + Soultrap = 58, + Telekinesis = 59, + Mark = 60, + Recall = 61, + DivineIntervention = 62, + AlmsiviIntervention = 63, + DetectAnimal = 64, + DetectEnchantment = 65, + DetectKey = 66, + SpellAbsorption = 67, + Reflect = 68, + CureCommonDisease = 69, + CureBlightDisease = 70, + CureCorprusDisease = 71, + CurePoison = 72, + CureParalyzation = 73, + RestoreAttribute = 74, + RestoreHealth = 75, + RestoreMagicka = 76, + RestoreFatigue = 77, + RestoreSkill = 78, + FortifyAttribute = 79, + FortifyHealth = 80, + FortifyMagicka= 81, + FortifyFatigue = 82, + FortifySkill = 83, + FortifyMaximumMagicka = 84, + AbsorbAttribute = 85, + AbsorbHealth = 86, + AbsorbMagicka = 87, + AbsorbFatigue = 88, + AbsorbSkill = 89, + ResistFire = 90, + ResistFrost = 91, + ResistShock = 92, + ResistMagicka = 93, + ResistCommonDisease = 94, + ResistBlightDisease = 95, + ResistCorprusDisease = 96, + ResistPoison = 97, + ResistNormalWeapons = 98, + ResistParalysis = 99, + RemoveCurse = 100, + TurnUndead = 101, + SummonScamp = 102, + SummonClannfear = 103, + SummonDaedroth = 104, + SummonDremora = 105, + SummonAncestralGhost = 106, + SummonSkeletalMinion = 107, + SummonBonewalker = 108, + SummonGreaterBonewalker = 109, + SummonBonelord = 110, + SummonWingedTwilight = 111, + SummonHunger = 112, + SummonGoldenSaint = 113, + SummonFlameAtronach = 114, + SummonFrostAtronach = 115, + SummonStormAtronach = 116, + FortifyAttack = 117, + CommandCreature = 118, + CommandHumanoid = 119, + BoundDagger = 120, + BoundLongsword = 121, + BoundMace = 122, + BoundBattleAxe = 123, + BoundSpear = 124, + BoundLongbow = 125, + ExtraSpell = 126, + BoundCuirass = 127, + BoundHelm = 128, + BoundBoots = 129, + BoundShield = 130, + BoundGloves = 131, + Corprus = 132, + Vampirism = 133, + SummonCenturionSphere = 134, + SunDamage = 135, + StuntedMagicka = 136, + + // Tribunal only + SummonFabricant = 137, + + // Bloodmoon only + SummonWolf = 138, + SummonBear = 139, + SummonBonewolf = 140, + SummonCreature04 = 141, + SummonCreature05 = 142 + }; }; } #endif From c07b3ea61d96b918be9df6cdd23df9691e52ee77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Mar 2013 04:20:30 +0100 Subject: [PATCH 0729/1483] Text defines for npc race, class, and faction should use the translated name --- apps/openmw/mwscript/interpretercontext.cpp | 9 ++++++--- apps/openmw/mwscript/interpretercontext.hpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index c74e3f1633..cad143c469 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -215,19 +215,22 @@ namespace MWScript std::string InterpreterContext::getNPCRace() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mRace); + return race->mName; } std::string InterpreterContext::getNPCClass() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mClass; + const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mClass); + return class_->mName; } std::string InterpreterContext::getNPCFaction() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mFaction; + const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mFaction); + return faction->mName; } std::string InterpreterContext::getNPCRank() const diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index f0b2758d9e..9c7b443ae1 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -89,7 +89,7 @@ namespace MWScript virtual std::string getNPCClass() const; virtual std::string getNPCFaction() const; - + virtual std::string getNPCRank() const; virtual std::string getPCName() const; From 52ed451ae7875971dbf0b4aa5c1d6252af63fef8 Mon Sep 17 00:00:00 2001 From: greye Date: Sun, 17 Mar 2013 08:36:15 +0400 Subject: [PATCH 0730/1483] fix eraseStatic() assumptions --- apps/openmw/mwworld/store.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 20646e6dad..f69f606b45 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -192,11 +192,14 @@ namespace MWWorld if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { // delete from the static part of mShared typename std::vector::iterator sharedIter = mShared.begin(); - for (; sharedIter != (mShared.begin()+mStatic.size()); ++sharedIter) { + typename std::vector::iterator end = sharedIter + mStatic.size(); + + while (sharedIter != mShared.end() && sharedIter != end) { if((*sharedIter)->mId == item.mId) { mShared.erase(sharedIter); break; } + ++sharedIter; } mStatic.erase(it); } From ea7f386e7d5d28958f004e70820f5e125d32e766 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 13:50:15 +0100 Subject: [PATCH 0731/1483] Access to Fallback via getFallback --- apps/openmw/mwbase/world.hpp | 3 ++- apps/openmw/mwgui/charactercreation.cpp | 12 ++++++------ apps/openmw/mwgui/levelupdialog.cpp | 5 +++-- apps/openmw/mwworld/worldimp.cpp | 10 +++++----- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 642291eefb..1d6b290c80 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -46,6 +46,7 @@ namespace MWRender namespace MWWorld { + class Fallback; class CellStore; class Player; class LocalScripts; @@ -103,7 +104,7 @@ namespace MWBase virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual std::string getFallback (const std::string& key) const = 0; + virtual MWWorld::Fallback *getFallback () = 0; virtual MWWorld::Player& getPlayer() = 0; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index b98fd2bd9f..5bc89fbd1b 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -12,6 +12,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwworld/fallback.hpp" namespace { @@ -23,14 +24,13 @@ namespace }; const ESM::Class::Specialization mSpecializations[3]={ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}; // The specialization for each answer - Step sGenerateClassSteps(int number) { - MWBase::World *world = MWBase::Environment::get().getWorld(); number++; - Step step = {world->getFallback("Question_"+boost::lexical_cast(number)+"_Question"), - {world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerOne"), - world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), - world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, + MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + Step step = {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_Question"), + {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerOne"), + fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), + fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, "vo\\misc\\chargen qa"+boost::lexical_cast(number)+".wav" }; return step; diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 9473f48b4e..f0a3858084 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -9,6 +9,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/fallback.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" @@ -138,9 +139,9 @@ namespace MWGui std::string levelupdescription; if(level>20) - levelupdescription=world->getFallback("Level_Up_Default"); + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); else - levelupdescription=world->getFallback("Level_Up_Level"+boost::lexical_cast(level)); + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+boost::lexical_cast(level)); mLevelDescription->setCaption (levelupdescription); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5a23aae972..ee41afc58a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -154,11 +154,6 @@ namespace MWWorld mRendering->skyDisable(); } - std::string World::getFallback (const std::string& key) const - { - return mFallback.getFallbackString(key); - } - World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::vector& master, const std::vector& plugins, @@ -267,6 +262,11 @@ namespace MWWorld return 0; } + MWWorld::Fallback *World::getFallback () + { + return &mFallback; + } + Ptr::CellStore *World::getExterior (int x, int y) { return mCells.getExterior (x, y); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 526e68a77a..d2db653db1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -133,7 +133,7 @@ namespace MWWorld virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual std::string getFallback (const std::string& key) const; + virtual Fallback *getFallback (); virtual Player& getPlayer(); From 6165cd2c6b7fd0deafe391579e4109e3aa5197a4 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 14:22:30 +0100 Subject: [PATCH 0732/1483] Moons fallbacks partially implemented --- apps/openmw/mwrender/sky.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 604ad50d22..ff2ef2a4f7 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -21,6 +21,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/fallback.hpp" + #include "renderconst.hpp" #include "renderingmanager.hpp" @@ -266,11 +268,12 @@ void SkyManager::create() mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); - mSecunda = new Moon("secunda_texture", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + mSecunda = new Moon("secunda_texture", /*0.5*/fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); - mMasser = new Moon("masser_texture", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mMasser = new Moon("masser_texture", /*0.75*/fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mMasser->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); @@ -368,7 +371,7 @@ int SkyManager::getSecundaPhase() const void SkyManager::update(float duration) { if (!mEnabled) return; - + MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); mCamera->getParentSceneNode ()->needUpdate (); mRootNode->setPosition(mCamera->getDerivedPosition()); @@ -381,7 +384,7 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setColour ( mMoonRed ? ColourValue(1.0, 0.0784, 0.0784) : ColourValue(1,1,1,1)); + mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) From 1369090a80fac639095e8ff358f7892332ba1038 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 14:50:02 +0100 Subject: [PATCH 0733/1483] More moons fallbacks, minor weather fixes --- apps/openmw/mwworld/weather.cpp | 72 +++++++-------------------------- 1 file changed, 14 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 867e910fe3..ea0270197f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -110,60 +110,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa /* Weather snow; snow.mCloudTexture = "tx_bm_sky_snow.dds"; - snow.mCloudsMaximumPercent = 1.0; - snow.mTransitionDelta = 0.014; - snow.mSkySunriseColor = clr(196, 91, 91); - snow.mSkyDayColor = clr(153, 158, 166); - snow.mSkySunsetColor = clr(96, 115, 134); - snow.mSkyNightColor = clr(31, 35, 39); - snow.mFogSunriseColor = clr(106, 91, 91); - snow.mFogDayColor = clr(153, 158, 166); - snow.mFogSunsetColor = clr(96, 115, 134); - snow.mFogNightColor = clr(31, 35, 39); - snow.mAmbientSunriseColor = clr(92, 84, 84); - snow.mAmbientDayColor = clr(93, 96, 105); - snow.mAmbientSunsetColor = clr(70, 79, 87); - snow.mAmbientNightColor = clr(49, 58, 68); - snow.mSunSunriseColor = clr(141, 109, 109); - snow.mSunDayColor = clr(163, 169, 183); - snow.mSunSunsetColor = clr(101, 121, 141); - snow.mSunNightColor = clr(55, 66, 77); - snow.mSunDiscSunsetColor = clr(128, 128, 128); - snow.mLandFogDayDepth = 1.0; - snow.mLandFogNightDepth = 1.2; - snow.mWindSpeed = 0; - snow.mCloudSpeed = 1.5; - snow.mGlareView = 0; - mWeatherSettings["snow"] = snow; + setFallbackWeather(snow, "snow") Weather blizzard; blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds"; - blizzard.mCloudsMaximumPercent = 1.0; - blizzard.mTransitionDelta = 0.030; - blizzard.mSkySunriseColor = clr(91, 99, 106); - blizzard.mSkyDayColor = clr(121, 133, 145); - blizzard.mSkySunsetColor = clr(108, 115, 121); - blizzard.mSkyNightColor = clr(27, 29, 31); - blizzard.mFogSunriseColor = clr(91, 99, 106); - blizzard.mFogDayColor = clr(121, 133, 145); - blizzard.mFogSunsetColor = clr(108, 115, 121); - blizzard.mFogNightColor = clr(21, 24, 28); - blizzard.mAmbientSunriseColor = clr(84, 88, 92); - blizzard.mAmbientDayColor = clr(93, 96, 105); - blizzard.mAmbientSunsetColor = clr(83, 77, 75); - blizzard.mAmbientNightColor = clr(53, 62, 70); - blizzard.mSunSunriseColor = clr(114, 128, 146); - blizzard.mSunDayColor = clr(163, 169, 183); - blizzard.mSunSunsetColor = clr(106, 114, 136); - blizzard.mSunNightColor = clr(57, 66, 74); - blizzard.mSunDiscSunsetColor = clr(128, 128, 128); - blizzard.mLandFogDayDepth = 2.8; - blizzard.mLandFogNightDepth = 3.0; - blizzard.mWindSpeed = 0.9; - blizzard.mCloudSpeed = 7.5; - blizzard.mGlareView = 0; blizzard.mAmbientLoopSoundID = "BM Blizzard"; - mWeatherSettings["blizzard"] = blizzard; + setFallbackWeather(blizzard,"blizzard") */ } @@ -471,20 +423,24 @@ void WeatherManager::update(float duration) else hour_fade = 1; - float secunda_angle_fade; - float masser_angle_fade; float angle = moonHeight*90.f; - if (angle >= 30 && angle <= 50) - secunda_angle_fade = (angle-30)/20.f; - else if (angle <30) + float secunda_angle_fade; + float secunda_end_angle=mFallback->getFallbackFloat("Moons_Secunda_Fade_End_Angle"); + float secunda_start_angle=mFallback->getFallbackFloat("Moons_Secunda_Fade_Start_Angle"); + if (angle >= secunda_end_angle && angle <= secunda_start_angle) + secunda_angle_fade = (angle-secunda_end_angle)/20.f; + else if (angle < secunda_end_angle) secunda_angle_fade = 0.f; else secunda_angle_fade = 1.f; - if (angle >= 40 && angle <= 50) - masser_angle_fade = (angle-40)/10.f; - else if (angle <40) + float masser_angle_fade; + float masser_end_angle=mFallback->getFallbackFloat("Moons_Masser_Fade_End_Angle"); + float masser_start_angle=mFallback->getFallbackFloat("Moons_Masser_Fade_Start_Angle"); + if (angle >= masser_end_angle && angle <= masser_start_angle) + masser_angle_fade = (angle-masser_end_angle)/10.f; + else if (angle < masser_end_angle) masser_angle_fade = 0.f; else masser_angle_fade = 1.f; From 46bde604f9fe4dec594d7e087d8b7956f66fc2a4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Mar 2013 17:13:25 +0100 Subject: [PATCH 0734/1483] Issue #601: unary minus was interpreted as binary minus when used in an argument list without comma --- components/compiler/exprparser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 027f3de712..94240c5eb9 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -603,8 +603,8 @@ namespace Compiler switch (code) { - case Scanner::S_plus: pushBinaryOperator ('+'); return true; - case Scanner::S_minus: pushBinaryOperator ('-'); return true; + case Scanner::S_plus: c = '+'; break; + case Scanner::S_minus: c = '-'; break; case Scanner::S_mult: pushBinaryOperator ('*'); return true; case Scanner::S_div: pushBinaryOperator ('/'); return true; case Scanner::S_cmpEQ: c = 'e'; break; From f3fd3a7691a4e13a4152dfa1c5fe520c2bffd91e Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 19:36:14 +0100 Subject: [PATCH 0735/1483] Much more moons fallbacks --- apps/openmw/mwworld/weather.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index ea0270197f..f7e8566751 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -415,13 +415,28 @@ void WeatherManager::update(float duration) mRendering->getSkyManager()->masserEnable(); mRendering->getSkyManager()->secundaEnable(); - float hour_fade; - if (mHour >= 7.f && mHour <= 14.f) - hour_fade = 1-(mHour-7)/3.f; - else if (mHour >= 14 && mHour <= 15.f) - hour_fade = mHour-14; + float secunda_hour_fade; + float secunda_fadeout_start=mFallback->getFallbackFloat("Moons_Secunda_Fade_Out_Start"); + float secunda_fadein_start=mFallback->getFallbackFloat("Moons_Secunda_Fade_In_Start"); + float secunda_fadein_finish=mFallback->getFallbackFloat("Moons_Secunda_Fade_In_Finish"); + + if (mHour >= secunda_fadeout_start && mHour <= secunda_fadein_start) + secunda_hour_fade = 1-(mHour-secunda_fadeout_start)/3.f; + else if (mHour >= secunda_fadein_start && mHour <= secunda_fadein_finish) + secunda_hour_fade = mHour-secunda_fadein_start; else - hour_fade = 1; + secunda_hour_fade = 1; + + float masser_hour_fade; + float masser_fadeout_start=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Start"); + float masser_fadein_start=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); + float masser_fadein_finish=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Finish"); + if (mHour >= masser_fadeout_start && mHour <= masser_fadein_start) + masser_hour_fade = 1-(mHour-masser_fadeout_start)/3.f; + else if (mHour >= masser_fadein_start && mHour <= masser_fadein_finish) + masser_hour_fade = mHour-masser_fadein_start; + else + masser_hour_fade = 1; float angle = moonHeight*90.f; @@ -445,8 +460,8 @@ void WeatherManager::update(float duration) else masser_angle_fade = 1.f; - masser_angle_fade *= hour_fade; - secunda_angle_fade *= hour_fade; + masser_angle_fade *= masser_hour_fade; + secunda_angle_fade *= secunda_hour_fade; mRendering->getSkyManager()->setMasserFade(masser_angle_fade); mRendering->getSkyManager()->setSecundaFade(secunda_angle_fade); From 5922637c58bbf58378104e52f04ac31443b5ef15 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 20:12:26 +0100 Subject: [PATCH 0736/1483] Unblocked Solstheim weather that should work now. --- apps/openmw/mwworld/weather.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index f7e8566751..5aaf40dc55 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -107,16 +107,14 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa blight.mAmbientLoopSoundID = "blight"; setFallbackWeather(blight,"blight"); - /* Weather snow; snow.mCloudTexture = "tx_bm_sky_snow.dds"; - setFallbackWeather(snow, "snow") + setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds"; blizzard.mAmbientLoopSoundID = "BM Blizzard"; - setFallbackWeather(blizzard,"blizzard") - */ + setFallbackWeather(blizzard,"blizzard"); } void WeatherManager::setWeather(const String& weather, bool instant) From c66675b5997f104b2de753fecb96bfbc82e0def5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Mar 2013 22:28:28 +0100 Subject: [PATCH 0737/1483] Fix the 'Take all' button taking equipped items when stealing --- apps/openmw/mwgui/container.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2b80003127..e476865433 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -683,12 +683,18 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) // transfer everything into the player's inventory MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + std::vector equippedItems = getEquippedItems(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); int i=0; for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) { + if (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() + && !mDisplayEquippedItems) + continue; + playerStore.add(*iter); if (i==0) @@ -698,11 +704,11 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } + iter->getRefData().setCount(0); + ++i; } - containerStore.clear(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } } From 95e1cdc07ddd1443522695f20617b5c110169ea7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Mar 2013 22:29:12 +0100 Subject: [PATCH 0738/1483] Move getArmorRating to MWWorld::Class. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 -- apps/openmw/mwclass/creature.cpp | 6 +++ apps/openmw/mwclass/creature.hpp | 3 ++ apps/openmw/mwclass/npc.cpp | 49 +++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 3 ++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 48 ------------------ .../mwmechanics/mechanicsmanagerimp.hpp | 3 -- apps/openmw/mwworld/class.cpp | 7 ++- apps/openmw/mwworld/class.hpp | 3 ++ 10 files changed, 71 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 6cb7c69188..020647744b 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -83,9 +83,6 @@ namespace MWBase virtual int getDerivedDisposition(const MWWorld::Ptr& ptr) = 0; ///< Calculate the diposition of an NPC toward the player. - virtual float getArmorRating (const MWWorld::Ptr& ptr) = 0; - ///< Calculate the combined armor rating of an NPC. - virtual int countDeaths (const std::string& id) const = 0; ///< Return the number of deaths for actors with the given ID. diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1b6212a238..1097f8f29c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -191,6 +191,12 @@ namespace MWClass return info; } + float Creature::getArmorRating (const MWWorld::Ptr& ptr) const + { + /// \todo add Shield magic effect magnitude here, controlled by a GMST (Vanilla vs MCP behaviour) + return 0.f; + } + float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index a96c18a8c5..ea356165eb 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -54,6 +54,9 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual bool isEssential (const MWWorld::Ptr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d931b9e2ea..a5319ada07 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -505,6 +505,55 @@ namespace MWClass stats.useSkill (skill, *class_, usageType); } + float Npc::getArmorRating (const MWWorld::Ptr& ptr) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + int ratings[MWWorld::InventoryStore::Slots]; + + int iBaseArmorSkill = gmst.find("iBaseArmorSkill")->getInt(); + float fUnarmoredBase1 = gmst.find("fUnarmoredBase1")->getFloat(); + float fUnarmoredBase2 = gmst.find("fUnarmoredBase2")->getFloat(); + int unarmoredSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(ESM::Skill::Unarmored).getModified(); + + for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(i); + if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) + { + // unarmored + ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + } + else + { + MWWorld::LiveCellRef *ref = + it->get(); + + int armorSkillType = MWWorld::Class::get(*it).getEquipmentSkill(*it); + int armorSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(armorSkillType).getModified(); + + if (ref->mBase->mData.mWeight == 0) + ratings[i] = ref->mBase->mData.mArmor; + else + ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + } + + float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Shield).mMagnitude; + + return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 + + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] + + ratings[MWWorld::InventoryStore::Slot_Greaves] + ratings[MWWorld::InventoryStore::Slot_Boots] + + ratings[MWWorld::InventoryStore::Slot_LeftPauldron] + ratings[MWWorld::InventoryStore::Slot_RightPauldron] + ) * 0.1 + + (ratings[MWWorld::InventoryStore::Slot_LeftGauntlet] + MWWorld::InventoryStore::Slot_RightGauntlet) + * 0.05 + + shield; + } + + void Npc::adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const { y = 0; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 0ca6a8d69e..0f61fc8c91 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -104,6 +104,9 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual bool apply (const MWWorld::Ptr& ptr, const std::string& id, const MWWorld::Ptr& actor) const; ///< Apply \a id on \a ptr. diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 2caed79728..29966bd08a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -292,7 +292,7 @@ namespace MWGui mAvatarImage->setImageTexture("CharacterPreview"); mArmorRating->setCaptionWithReplacing ("#{sArmor}: " - + boost::lexical_cast(static_cast(MWBase::Environment::get().getMechanicsManager()->getArmorRating(mPtr)))); + + boost::lexical_cast(static_cast(MWWorld::Class::get(mPtr).getArmorRating(mPtr)))); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index ac470fbbac..32fa58980d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -669,52 +669,4 @@ namespace MWMechanics mActors.skipAnimation(ptr); } - float MechanicsManager::getArmorRating(const MWWorld::Ptr &ptr) - { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - - int ratings[MWWorld::InventoryStore::Slots]; - - int iBaseArmorSkill = gmst.find("iBaseArmorSkill")->getInt(); - float fUnarmoredBase1 = gmst.find("fUnarmoredBase1")->getFloat(); - float fUnarmoredBase2 = gmst.find("fUnarmoredBase2")->getFloat(); - int unarmoredSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(ESM::Skill::Unarmored).getModified(); - - for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i) - { - MWWorld::ContainerStoreIterator it = invStore.getSlot(i); - if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) - { - // unarmored - ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); - } - else - { - MWWorld::LiveCellRef *ref = - it->get(); - - int armorSkillType = MWWorld::Class::get(*it).getEquipmentSkill(*it); - int armorSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(armorSkillType).getModified(); - - if (ref->mBase->mData.mWeight == 0) - ratings[i] = ref->mBase->mData.mArmor; - else - ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; - } - } - - float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Shield).mMagnitude; - - return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 - + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] - + ratings[MWWorld::InventoryStore::Slot_Greaves] + ratings[MWWorld::InventoryStore::Slot_Boots] - + ratings[MWWorld::InventoryStore::Slot_LeftPauldron] + ratings[MWWorld::InventoryStore::Slot_RightPauldron] - ) * 0.1 - + (ratings[MWWorld::InventoryStore::Slot_LeftGauntlet] + MWWorld::InventoryStore::Slot_RightGauntlet) - * 0.05 - + shield; - } - } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 2e09c5f8e5..5ad8705719 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,9 +88,6 @@ namespace MWMechanics virtual int getDerivedDisposition(const MWWorld::Ptr& ptr); ///< Calculate the diposition of an NPC toward the player. - virtual float getArmorRating (const MWWorld::Ptr& ptr); - ///< Calculate the combined armor rating of an NPC. - virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 71b24b65dc..985d35d45e 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -167,11 +167,16 @@ namespace MWWorld return false; } - bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const + bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const { return false; } + float Class::getArmorRating (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error("Class does not support armor rating"); + } + const Class& Class::get (const std::string& key) { std::map >::const_iterator iter = sClasses.find (key); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1a6a16ca07..53dbeff862 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -215,6 +215,9 @@ namespace MWWorld ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + virtual float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. From 08f6d04960f426d80e42e5b9e4c1251ee58fb467 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 08:29:40 +0100 Subject: [PATCH 0739/1483] constness fixes --- apps/openmw/mwbase/world.hpp | 6 +++--- apps/openmw/mwgui/charactercreation.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 1d6b290c80..f3b817e516 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -104,7 +104,7 @@ namespace MWBase virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual MWWorld::Fallback *getFallback () = 0; + virtual const MWWorld::Fallback *getFallback () const = 0; virtual MWWorld::Player& getPlayer() = 0; @@ -139,7 +139,7 @@ namespace MWBase virtual char getGlobalVariableType (const std::string& name) const = 0; ///< Return ' ', if there is no global variable with this name. - + virtual std::vector getGlobals () const = 0; virtual std::string getCurrentCellName() const = 0; @@ -296,7 +296,7 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual void renderPlayer() = 0; - + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; virtual int canRest() = 0; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 5bc89fbd1b..0cc12170ac 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -26,7 +26,7 @@ namespace const ESM::Class::Specialization mSpecializations[3]={ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}; // The specialization for each answer Step sGenerateClassSteps(int number) { number++; - MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); Step step = {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_Question"), {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerOne"), fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index ff2ef2a4f7..94af3521b3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -268,7 +268,7 @@ void SkyManager::create() mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); - MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); mSecunda = new Moon("secunda_texture", /*0.5*/fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); @@ -371,7 +371,7 @@ int SkyManager::getSecundaPhase() const void SkyManager::update(float duration) { if (!mEnabled) return; - MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); mCamera->getParentSceneNode ()->needUpdate (); mRootNode->setPosition(mCamera->getDerivedPosition()); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 63e0f14d63..0a874513c3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -262,7 +262,7 @@ namespace MWWorld return 0; } - MWWorld::Fallback *World::getFallback () + const MWWorld::Fallback *World::getFallback() const { return &mFallback; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d2db653db1..24565029fc 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -133,7 +133,7 @@ namespace MWWorld virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual Fallback *getFallback (); + virtual const Fallback *getFallback() const; virtual Player& getPlayer(); From 61cb0f98a60718d76c1e12f81c4b16a0c8930f71 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 10:46:45 +0100 Subject: [PATCH 0740/1483] keep track of death events --- apps/openmw/mwmechanics/creaturestats.cpp | 18 +++++++++++++++++- apps/openmw/mwmechanics/creaturestats.hpp | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 4be5d55b22..19d2080211 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -10,7 +10,8 @@ namespace MWMechanics { CreatureStats::CreatureStats() - : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), + : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mDied (false), mFriendlyHits (0), + mTalkedTo (false), mAlarmed (false), mAttacked (false), mHostile (false) { for (int i=0; i<4; ++i) @@ -167,7 +168,12 @@ namespace MWMechanics mDynamic[index] = value; if (index==0 && mDynamic[index].getCurrent()<1) + { + if (!mDead) + mDied = true; + mDead = true; + } } void CreatureStats::setLevel(int level) @@ -196,6 +202,16 @@ namespace MWMechanics return mDead; } + bool CreatureStats::hasDied() const + { + return mDied; + } + + void CreatureStats::clearHasDied() + { + mDied = false; + } + void CreatureStats::resurrect() { if (mDead) diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 3375c1af83..63de13d0d4 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -28,6 +28,7 @@ namespace MWMechanics AiSequence mAiSequence; float mLevelHealthBonus; bool mDead; + bool mDied; int mFriendlyHits; bool mTalkedTo; bool mAlarmed; @@ -100,6 +101,10 @@ namespace MWMechanics bool isDead() const; + bool hasDied() const; + + void clearHasDied(); + void resurrect(); bool hasCommonDisease() const; From fd2c07a6f47b26469d01d05b7a284aa87f9caef2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 10:54:47 +0100 Subject: [PATCH 0741/1483] delete death events on adding an actor to the scene --- apps/openmw/mwmechanics/actors.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index efbda83ee4..1480b3182e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -80,7 +80,7 @@ namespace MWMechanics DynamicStat magicka = creatureStats.getMagicka(); magicka.setBase (static_cast (intelligence + magickaFactor * intelligence)); creatureStats.setMagicka (magicka); - + DynamicStat fatigue = creatureStats.getFatigue(); fatigue.setBase (strength+willpower+agility+endurance); creatureStats.setFatigue (fatigue); @@ -95,7 +95,7 @@ namespace MWMechanics bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - + DynamicStat health = stats.getHealth(); health.setCurrent (health.getCurrent() + 0.1 * endurance); stats.setHealth (health); @@ -114,15 +114,15 @@ namespace MWMechanics float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); x *= fEndFatigueMult * endurance; - + DynamicStat fatigue = stats.getFatigue(); fatigue.setCurrent (fatigue.getCurrent() + 3600 * x); stats.setFatigue (fatigue); - + if (!stunted) { float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat (); - + DynamicStat magicka = stats.getMagicka(); magicka.setCurrent (magicka.getCurrent() + fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified()); @@ -148,22 +148,25 @@ namespace MWMechanics // dynamic stats MagicEffects effects = creatureStats.getMagicEffects(); - + for (int i=0; i<3; ++i) { DynamicStat stat = creatureStats.getDynamic (i); - + stat.setModifier ( effects.get (EffectKey(80+i)).mMagnitude - effects.get (EffectKey(18+i)).mMagnitude); - + creatureStats.setDynamic (i, stat); - } + } } Actors::Actors() : mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) { + // erase previous death events since we are currently only tracking them while in an active cell + MWWorld::Class::get (ptr).getCreatureStats (ptr).clearHasDied(); + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); @@ -277,7 +280,7 @@ namespace MWMechanics for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) calculateRestoration(iter->first, 3600); } - + int Actors::countDeaths (const std::string& id) const { std::map::const_iterator iter = mDeathCount.find(id); From e4ed5b836e10e663e2accb78c4d6176fa76e1876 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 11:04:47 +0100 Subject: [PATCH 0742/1483] added ondeath script function --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/statsextensions.cpp | 27 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 283f149de2..0f07b4d2e8 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -315,5 +315,6 @@ op 0x20001f8: Drop op 0x20001f9: Drop, explicit reference op 0x20001fa: DropSoulGem op 0x20001fb: DropSoulGem, explicit reference +op 0x20001fc: OnDeath -opcodes 0x20001fa-0x3ffffff unused +opcodes 0x20001fd-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 530d44c9dd..c5fc9436be 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1025,6 +1025,27 @@ namespace MWScript } }; + class OpOnDeath : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + Interpreter::Type_Integer value = + MWWorld::Class::get (ptr).getCreatureStats (ptr).hasDied(); + + if (value) + MWWorld::Class::get (ptr).getCreatureStats (ptr).clearHasDied(); + + runtime.push (value); + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -1114,6 +1135,8 @@ namespace MWScript const int opcodeLowerRank = 0x20001ea; const int opcodeLowerRankExplicit = 0x20001eb; + const int opcodeOnDeath = 0x20001fc; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -1227,6 +1250,8 @@ namespace MWScript extensions.registerInstruction ("pcclearexpelled", "/S", opcodePcClearExpelled, opcodePcClearExpelledExplicit); extensions.registerInstruction ("raiserank", "", opcodeRaiseRank, opcodeRaiseRankExplicit); extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); + + extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -1341,6 +1366,8 @@ namespace MWScript interpreter.installSegment5 (opcodeRaiseRankExplicit, new OpRaiseRank); interpreter.installSegment5 (opcodeLowerRank, new OpLowerRank); interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank); + + interpreter.installSegment5 (opcodeOnDeath, new OpOnDeath); } } } From 4711135e7f6ced616e0e6166337771cb6f6da9fc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 12:05:54 +0100 Subject: [PATCH 0743/1483] workaround for faulty endif in Morrowind scripts --- components/compiler/scriptparser.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index ac0ee63f1c..5b3d244b0d 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -2,6 +2,8 @@ #include "scriptparser.hpp" #include "scanner.hpp" +#include "skipparser.hpp" +#include "errorhandler.hpp" namespace Compiler { @@ -41,6 +43,17 @@ namespace Compiler return true; } + /// \todo add an option to disable this nonsense + if (keyword==Scanner::K_endif) + { + // surplus endif + getErrorHandler().warning ("endif without matching if/elseif", loc); + + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; + } + if (keyword==Scanner::K_end && mEnd) { return false; From f84db69ade1789a02531713db94f55de0deb8438 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 Mar 2013 19:46:20 +0100 Subject: [PATCH 0744/1483] Remove the background window trick, which currently doesn't serve any purpose --- libs/openengine/ogre/renderer.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index c4f35e0872..309ba8a060 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -229,15 +229,6 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& assert(mRoot); mRoot->initialise(false); - // create a hidden 1x1 background window to keep resources when recreating the secondary (real) window - NameValuePairList params_; - params_.insert(std::make_pair("title", title)); - params_.insert(std::make_pair("FSAA", "0")); - params_.insert(std::make_pair("vsync", "false")); - params_.insert(std::make_pair("hidden", "true")); - Ogre::RenderWindow* hiddenWindow = mRoot->createRenderWindow("InactiveHidden", 1, 1, false, ¶ms_); - hiddenWindow->setActive(false); - NameValuePairList params; params.insert(std::make_pair("title", title)); params.insert(std::make_pair("FSAA", settings.fsaa)); From a07c910d0bca8318c03d147f5330c953155b4b7f Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 18 Mar 2013 21:33:12 +0100 Subject: [PATCH 0745/1483] Feature #535: Console object selection improvements --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/tooltips.cpp | 31 +++++++++++++++++++++++--- apps/openmw/mwgui/windowmanagerimp.cpp | 7 ++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 ++++- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 93cc8e44a2..cd28bb47e7 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -91,6 +91,8 @@ namespace MWBase virtual bool isGuiMode() const = 0; + virtual bool isConsoleMode() const = 0; + virtual void toggleVisible (MWGui::GuiWindow wnd) = 0; /// Disallow all inventory mode windows diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 8eb0336a79..6a2550e4f5 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -81,8 +81,33 @@ void ToolTips::onFrame(float frameDuration) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Console) - || (mWindowManager->getMode() == GM_Container) + if (mWindowManager->getWorldMouseOver() && (mWindowManager->getMode() == GM_Console)) + { + MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); + if (!object.isEmpty()) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=object.getCellRef().mRefID; + info.icon=""; + IntSize tooltipSize = createToolTip(info); + IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); + + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - tooltipSize.width; + } + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - tooltipSize.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + } + } + + if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Container) || (mWindowManager->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); @@ -90,7 +115,7 @@ void ToolTips::onFrame(float frameDuration) if (mFocusObject.isEmpty ()) return; - MyGUI::IntSize tooltipSize = getToolTipViaPtr(true); + IntSize tooltipSize = getToolTipViaPtr(true); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3da739e260..b7d6ed1c9b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1020,6 +1020,13 @@ bool WindowManager::isGuiMode() const return !mGuiModes.empty(); } +bool WindowManager::isConsoleMode() const +{ + if (mGuiModes.back()==GM_Console) + return true; + return false; +} + MWGui::GuiMode WindowManager::getMode() const { if (mGuiModes.empty()) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 122b10cc39..a7baf5207e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -102,6 +102,8 @@ namespace MWGui virtual bool isGuiMode() const; + virtual bool isConsoleMode() const; + virtual void toggleVisible(GuiWindow wnd); // Disallow all inventory mode windows diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0a874513c3..73bb10a48f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -671,11 +671,12 @@ namespace MWWorld return MWWorld::Ptr (); MWWorld::Ptr object = searchPtrViaHandle (result.second); - float ActivationDistance; if (object.getTypeName ().find("NPC") != std::string::npos) ActivationDistance = getNpcActivationDistance (); + else if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) + ActivationDistance = getObjectActivationDistance ()*50; else ActivationDistance = getObjectActivationDistance (); @@ -1010,6 +1011,8 @@ namespace MWWorld float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()); + if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) + results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()*50); } else { From f5bf7254a8febba57f747d8a1773e32ad36b803a Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 18 Mar 2013 23:46:17 +0100 Subject: [PATCH 0746/1483] Minor console selection improvements --- apps/openmw/mwgui/tooltips.cpp | 23 +++++++++++++++-------- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 6a2550e4f5..1455be8b0f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -83,15 +83,22 @@ void ToolTips::onFrame(float frameDuration) if (mWindowManager->getWorldMouseOver() && (mWindowManager->getMode() == GM_Console)) { - MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); - if (!object.isEmpty()) + MWWorld::Ptr objectptr = MWBase::Environment::get().getWorld()->getFacedObject(); + if (!objectptr.isEmpty()) { - setCoord(0, 0, 300, 300); - mDynamicToolTipBox->setVisible(true); - ToolTipInfo info; - info.caption=object.getCellRef().mRefID; - info.icon=""; - IntSize tooltipSize = createToolTip(info); + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + IntSize tooltipSize; + if (!objectclass.hasToolTip(mFocusObject)) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=objectptr.getCellRef().mRefID; + info.icon=""; + tooltipSize = createToolTip(info); + } + else + tooltipSize = getToolTipViaPtr(true); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 73bb10a48f..1b5dc3bd35 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -673,10 +673,10 @@ namespace MWWorld MWWorld::Ptr object = searchPtrViaHandle (result.second); float ActivationDistance; - if (object.getTypeName ().find("NPC") != std::string::npos) - ActivationDistance = getNpcActivationDistance (); - else if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) + if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) ActivationDistance = getObjectActivationDistance ()*50; + else if (object.getTypeName ().find("NPC") != std::string::npos) + ActivationDistance = getNpcActivationDistance (); else ActivationDistance = getObjectActivationDistance (); From e76d03dcc43f924bd50aefcd34b926000855e08e Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 19 Mar 2013 12:01:54 +0100 Subject: [PATCH 0747/1483] Added a warning message to the importer dialog --- apps/launcher/maindialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 1a5b4d2e93..e5da3431ab 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -182,8 +182,9 @@ bool MainDialog::showFirstRunDialog() Q_UNUSED(skipButton); // Surpress compiler unused warning msgBox.setStandardButtons(QDialogButtonBox::NoButton); - msgBox.setText(tr("
An existing Morrowind configuration was detected

\ - Would you like to import settings from Morrowind.ini?
")); + msgBox.setText(tr("
An existing Morrowind configuration was detected
\ +
Would you like to import settings from Morrowind.ini?
\ +
Warning: In most cases OpenMW needs these settings to run properly
")); msgBox.setCheckBoxText(tr("Include selected masters and plugins (creates a new profile)")); msgBox.exec(); From dd11ae04ee9501e270b2ead3c943f9e08ebeb927 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 19 Mar 2013 17:25:41 +0100 Subject: [PATCH 0748/1483] Console code cleaned --- apps/openmw/mwgui/tooltips.cpp | 50 ++++++++++------------------------ 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 1455be8b0f..a8f228ff8b 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -81,48 +81,28 @@ void ToolTips::onFrame(float frameDuration) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - if (mWindowManager->getWorldMouseOver() && (mWindowManager->getMode() == GM_Console)) - { - MWWorld::Ptr objectptr = MWBase::Environment::get().getWorld()->getFacedObject(); - if (!objectptr.isEmpty()) - { - const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); - IntSize tooltipSize; - if (!objectclass.hasToolTip(mFocusObject)) - { - setCoord(0, 0, 300, 300); - mDynamicToolTipBox->setVisible(true); - ToolTipInfo info; - info.caption=objectptr.getCellRef().mRefID; - info.icon=""; - tooltipSize = createToolTip(info); - } - else - tooltipSize = getToolTipViaPtr(true); - IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - - if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) - { - tooltipPosition.left = viewSize.width - tooltipSize.width; - } - if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) - { - tooltipPosition.top = viewSize.height - tooltipSize.height; - } - - setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); - } - } - - if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Container) + if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Console) + || (mWindowManager->getMode() == GM_Container) || (mWindowManager->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); if (mFocusObject.isEmpty ()) return; - IntSize tooltipSize = getToolTipViaPtr(true); + IntSize tooltipSize; + if ((!objectclass.hasToolTip(mFocusObject))&&(mWindowManager->getMode() == GM_Console)) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=mFocusObject.getCellRef().mRefID; + info.icon=""; + tooltipSize = createToolTip(info); + } + else + tooltipSize = getToolTipViaPtr(true); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); From 3bd545ed8e6861264ef17961d4b9b98726fc3793 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 19 Mar 2013 21:55:37 +0100 Subject: [PATCH 0749/1483] In-console nonexistent class fix --- apps/openmw/mwgui/tooltips.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a8f228ff8b..af3e146bba 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -86,11 +86,12 @@ void ToolTips::onFrame(float frameDuration) || (mWindowManager->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); - const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); if (mFocusObject.isEmpty ()) return; + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + IntSize tooltipSize; if ((!objectclass.hasToolTip(mFocusObject))&&(mWindowManager->getMode() == GM_Console)) { From 21cc7483e46338341db0c65ae5838a2ffacc2618 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 01:20:56 +0100 Subject: [PATCH 0750/1483] Fix broken weather transitions --- apps/openmw/mwworld/weather.cpp | 75 +++++++++++++++++++-------------- apps/openmw/mwworld/weather.hpp | 1 + 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 052ae4e028..c74150bf82 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -18,7 +18,18 @@ using namespace Ogre; using namespace MWWorld; using namespace MWSound; -#define lerp(x, y) (x * (1-factor) + y * factor) +namespace +{ + float lerp (float x, float y, float factor) + { + return x * (1-factor) + y * factor; + } + Ogre::ColourValue lerp (const Ogre::ColourValue& x, const Ogre::ColourValue& y, float factor) + { + return x * (1-factor) + y * factor; + } +} + std::string WeatherManager::getFallback (const std::string& key) const { std::map::const_iterator it; @@ -51,6 +62,7 @@ ColourValue WeatherManager::getFallbackColour(const std::string& fall) const } return ColourValue(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); } + void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { std::string upper=name; @@ -98,7 +110,8 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,const std:: mSunsetTime = getFallbackFloat("Weather_Sunset_Time"); mSunriseDuration = getFallbackFloat("Weather_Sunrise_Duration"); mSunsetDuration = getFallbackFloat("Weather_Sunset_Duration"); - mWeatherUpdateTime = getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mHoursBetweenWeatherChanges = getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mWeatherUpdateTime = mHoursBetweenWeatherChanges*3600; mThunderFrequency = getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); mThunderThreshold = getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); mThunderSoundDelay = 0.25; @@ -263,10 +276,10 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade in float advance = 6-mHour; float factor = advance / 0.5f; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor); + result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); + result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); + result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); + result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); result.mNightFade = factor; } else //if (mHour >= 6) @@ -274,10 +287,10 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade out float advance = mHour-6; float factor = advance / 3.f; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor); + result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); + result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); + result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); + result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); } } @@ -298,20 +311,20 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade in float advance = 19-mHour; float factor = (advance / 2); - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor); + result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); + result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); + result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); + result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); } else //if (mHour >= 19) { // fade out float advance = mHour-19; float factor = advance / 2.f; - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor); + result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); + result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); + result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); + result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); result.mNightFade = factor; } } @@ -329,19 +342,19 @@ WeatherResult WeatherManager::transition(float factor) result.mNextCloudTexture = other.mCloudTexture; result.mCloudBlendFactor = factor; - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); - result.mFogColor = lerp(current.mFogColor, other.mFogColor); - result.mSunColor = lerp(current.mSunColor, other.mSunColor); - result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor); + result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); + result.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); + result.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); + result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); - result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor); - result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor); - result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth); - result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed); - result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); - result.mGlareView = lerp(current.mGlareView, other.mGlareView); - result.mNightFade = lerp(current.mNightFade, other.mNightFade); + result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); + result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); + result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); + result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); + result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); + result.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); + result.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); result.mNight = current.mNight; @@ -365,7 +378,7 @@ void WeatherManager::update(float duration) if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { mCurrentRegion = regionstr; - mWeatherUpdateTime = mWeatherUpdateTime*3600; + mWeatherUpdateTime = mHoursBetweenWeatherChanges*3600; std::string weather = "clear"; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index b5bd0e10a0..284c0e0506 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -179,6 +179,7 @@ namespace MWWorld float mSunriseDuration; float mSunsetDuration; float mWeatherUpdateTime; + float mHoursBetweenWeatherChanges; float mThunderFrequency; float mThunderThreshold; float mThunderSoundDelay; From 2509b34ace037a65d0ecc5b205f69bc1c7c9b8f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 02:48:10 +0100 Subject: [PATCH 0751/1483] Enabled bloodmoon weather --- apps/openmw/mwworld/weather.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 35b5b59cf2..3e85253123 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -317,19 +317,19 @@ void WeatherManager::update(float duration) float thunder = region->mData.mThunder/255.f; float ash = region->mData.mAsh/255.f; float blight = region->mData.mBlight/255.f; - //float snow = region->mData.a/255.f; - //float blizzard = region->mData.b/255.f; + float snow = region->mData.mA/255.f; + float blizzard = region->mData.mB/255.f; // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; + const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; float random = ((rand()%100)/100.f) * total; - //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - // weather = "blizzard"; - //else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - // weather = "snow"; - /*else*/ if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) + if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "blizzard"; + else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "snow"; + else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) weather = "blight"; else if (random >= thunder+rain+overcast+foggy+cloudy+clear) weather = "ashstorm"; From b9c3a4816d118d490eec9e2a397d013b93accc2e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 03:30:15 +0100 Subject: [PATCH 0752/1483] Fix dialogue topics still being accessible in the history pane when they shouldn't be --- apps/openmw/mwgui/dialogue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index c500cd1747..0bbf7c7af4 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -175,6 +175,9 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) if (!mEnabled && color == "#572D21") MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + if (!mEnabled) + return; + if(color != "#B29154") { MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); From 4cbb20230617d8e3ca98cfd603d37eeafcf99532 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 03:31:01 +0100 Subject: [PATCH 0753/1483] Several tooltip fixes --- apps/openmw/mwgui/map_window.cpp | 12 +++++------ files/mygui/openmw_tooltips.layout | 32 ++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 52b108f850..d0f3f921e5 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -190,8 +190,8 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", marker.name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); markerWidget->setUserString("IsMarker", "true"); markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); @@ -323,16 +323,16 @@ void MapWindow::addVisitedLocation(const std::string& name, int x, int y) widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); ++_counter; markerWidget = mEventBoxGlobal->createWidget("", widgetCoord, MyGUI::Align::Default); markerWidget->setNeedMouseFocus (true); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); } void MapWindow::cellExplored(int x, int y) diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index f554e2b0d5..7291f2ca21 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -7,7 +7,17 @@ - + + + + + + + + + + + @@ -106,12 +116,14 @@ - + + - + + @@ -147,10 +159,12 @@ + - + + @@ -200,17 +214,23 @@ + + - + + - + + + + From 11aed7474eba3aeca00cebf77ccece3c126cfa74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 18:34:54 +0100 Subject: [PATCH 0754/1483] Shadow cast on water --- files/materials/water.mat | 19 +++++++++ files/materials/water.shader | 76 +++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/files/materials/water.mat b/files/materials/water.mat index 0ec71d2df7..1e5f8c8e04 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -54,5 +54,24 @@ material Water scale 0.1 0.1 alpha_op_ex source1 src_manual src_current 0.7 } + + texture_unit shadowMap0 + { + content_type shadow + tex_address_mode clamp + filtering none + } + texture_unit shadowMap1 + { + content_type shadow + tex_address_mode clamp + filtering none + } + texture_unit shadowMap2 + { + content_type shadow + tex_address_mode clamp + filtering none + } } } diff --git a/files/materials/water.shader b/files/materials/water.shader index 793cdc95e3..a6d0a47e6e 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -50,6 +50,13 @@ // Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) +#define SHADOWS_PSSM @shGlobalSettingBool(shadows_pssm) +#define SHADOWS @shGlobalSettingBool(shadows) + +#if SHADOWS || SHADOWS_PSSM + #include "shadows.h" +#endif + #define RIPPLES 1 #define REFRACTION @shGlobalSettingBool(refraction) @@ -64,6 +71,23 @@ shOutput(float4, position) shOutput(float, depthPassthrough) + +#if SHADOWS + shOutput(float4, lightSpacePos0) + shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) +#endif + +#if SHADOWS_PSSM + @shForeach(3) + shOutput(float4, lightSpacePos@shIterator) + shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) + @shEndForeach +#endif + +#if SHADOWS || SHADOWS_PSSM + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif + SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); @@ -88,6 +112,17 @@ position = shInputPosition; depthPassthrough = shOutputPosition.z; + + +#if SHADOWS + lightSpacePos0 = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); +#endif +#if SHADOWS_PSSM + float4 wPos = shMatrixMult(worldMatrix, shInputPosition); + @shForeach(3) + lightSpacePos@shIterator = shMatrixMult(texViewProjMatrix@shIterator, wPos); + @shEndForeach +#endif } #else @@ -186,10 +221,47 @@ shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position_object_space) + + +#if SHADOWS + shInput(float4, lightSpacePos0) + shSampler2D(shadowMap0) + shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, 1) +#endif +#if SHADOWS_PSSM + @shForeach(3) + shInput(float4, lightSpacePos@shIterator) + shSampler2D(shadowMap@shIterator) + shUniform(float2, invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator(1)) + @shEndForeach + shUniform(float3, pssmSplitPoints) @shSharedParameter(pssmSplitPoints) +#endif + +#if SHADOWS || SHADOWS_PSSM + shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) +#endif SH_START_PROGRAM { +#if SHADOWS + float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); +#endif +#if SHADOWS_PSSM + float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depthPassthrough, pssmSplitPoints); +#endif + +#if SHADOWS || SHADOWS_PSSM + float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; + float fade = 1-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); + shadow = (depthPassthrough > shadowFar_fadeStart.x) ? 1.0 : ((depthPassthrough > shadowFar_fadeStart.y) ? 1.0-((1.0-shadow)*fade) : shadow); +#endif + +#if !SHADOWS && !SHADOWS_PSSM + float shadow = 1.0; +#endif + + float2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1-shSaturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; @@ -244,7 +316,7 @@ float3 llR = reflect(lVec, pNormal); float s = shSaturate(dot(lR, vVec)*2.0-1.2); - float lightScatter = shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); + float lightScatter = shadow * shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*float3(1.0,0.4,0.0), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); // fresnel @@ -267,7 +339,7 @@ #endif // specular - float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); + float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; #if REFRACTION shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; From ad3478c8f276dc6c9546ef9fb79fbd322e565bef Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Mar 2013 02:02:09 +0100 Subject: [PATCH 0755/1483] Fix inverted dialogue functions (NotClass etc.) The comparison present is useless for these functions. --- apps/openmw/mwdialogue/filter.cpp | 11 +++++++++-- apps/openmw/mwdialogue/selectwrapper.cpp | 25 +++++++++++++----------- apps/openmw/mwdialogue/selectwrapper.hpp | 5 ++--- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 7b5f354a23..8e8ac4db5e 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -136,8 +136,12 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { - if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name()) - return select.isInverted(); + if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name())) + // If the actor is a creature, we do not test the conditions applicable + // only to NPCs. Such conditions can never be satisfied, apart + // inverted ones (NotClass, NotRace, NotFaction return true + // because creatures are not of any race, class or faction). + return select.getType() == SelectWrapper::Type_Inverted; switch (select.getType()) { @@ -145,6 +149,9 @@ bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const case SelectWrapper::Type_Integer: return select.selectCompare (getSelectStructInteger (select)); case SelectWrapper::Type_Numeric: return testSelectStructNumeric (select); case SelectWrapper::Type_Boolean: return select.selectCompare (getSelectStructBoolean (select)); + + // We must not do the comparison for inverted functions (eg. Function_NotClass) + case SelectWrapper::Type_Inverted: return getSelectStructBoolean (select); } return true; diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 77930ae423..81a4153601 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -219,7 +219,6 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function booleanFunctions[] = { Function_False, - Function_NotId, Function_NotFaction, Function_NotClass, Function_NotRace, Function_NotCell, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus, Function_PcExpelled, @@ -231,6 +230,13 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const Function_None // end marker }; + static const Function invertedBooleanFunctions[] = + { + Function_NotId, Function_NotFaction, Function_NotClass, + Function_NotRace, Function_NotCell, + Function_None // end marker + }; + Function function = getFunction(); for (int i=0; integerFunctions[i]!=Function_None; ++i) @@ -245,16 +251,13 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const if (booleanFunctions[i]==function) return Type_Boolean; + for (int i=0; invertedBooleanFunctions[i]!=Function_None; ++i) + if (invertedBooleanFunctions[i]==function) + return Type_Inverted; + return Type_None; } -bool MWDialogue::SelectWrapper::isInverted() const -{ - char type = mSelect.mSelectRule[1]; - - return type=='7' || type=='8' || type=='9' || type=='A' || type=='B' || type=='C'; -} - bool MWDialogue::SelectWrapper::isNpcOnly() const { static const Function functions[] = @@ -283,17 +286,17 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const bool MWDialogue::SelectWrapper::selectCompare (int value) const { - return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR + return selectCompareImp (mSelect, value); } bool MWDialogue::SelectWrapper::selectCompare (float value) const { - return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR + return selectCompareImp (mSelect, value); } bool MWDialogue::SelectWrapper::selectCompare (bool value) const { - return selectCompareImp (mSelect, static_cast (value))!=isInverted(); // logic XOR + return selectCompareImp (mSelect, static_cast (value)); } std::string MWDialogue::SelectWrapper::getName() const diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index c27339afa0..0548c60cbb 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -50,7 +50,8 @@ namespace MWDialogue Type_None, Type_Integer, Type_Numeric, - Type_Boolean + Type_Boolean, + Type_Inverted }; private: @@ -67,8 +68,6 @@ namespace MWDialogue Type getType() const; - bool isInverted() const; - bool isNpcOnly() const; ///< \attention Do not call any of the select functions for this select struct! From f25b56ac8867b32584295baa1112ffadf6e33187 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Mar 2013 02:06:06 +0100 Subject: [PATCH 0756/1483] Add dialogue function: NotLocal --- apps/openmw/mwdialogue/filter.cpp | 24 ++++++++++++++++++++++++ apps/openmw/mwdialogue/selectwrapper.cpp | 4 ++-- apps/openmw/mwdialogue/selectwrapper.hpp | 1 + 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 8e8ac4db5e..c2d0515dd7 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -440,6 +440,30 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)!=select.getName(); + case SelectWrapper::Function_NotLocal: + { + std::string scriptName = MWWorld::Class::get (mActor).getScript (mActor); + + if (scriptName.empty()) + // This actor has no attached script, so there is no local variable + return true; + + const ESM::Script *script = + MWBase::Environment::get().getWorld()->getStore().get().find (scriptName); + + std::string name = select.getName(); + + int i = 0; + for (; i < script->mVarNames.size(); ++i) + if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name) + break; + + if (i >= script->mVarNames.size()) + return true; // script does not have a variable of this name + + return false; + } + case SelectWrapper::Function_SameGender: return (player.get()->mBase->mFlags & ESM::NPC::Female)== diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 81a4153601..d48a06323e 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -117,7 +117,7 @@ MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() con case '9': return Function_NotClass; case 'A': return Function_NotRace; case 'B': return Function_NotCell; - case 'C': return Function_Local; + case 'C': return Function_NotLocal; } return Function_None; @@ -233,7 +233,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function invertedBooleanFunctions[] = { Function_NotId, Function_NotFaction, Function_NotClass, - Function_NotRace, Function_NotCell, + Function_NotRace, Function_NotCell, Function_NotLocal, Function_None // end marker }; diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index 0548c60cbb..f4bc898a4b 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -22,6 +22,7 @@ namespace MWDialogue Function_NotClass, Function_NotRace, Function_NotCell, + Function_NotLocal, Function_Local, Function_Global, Function_SameGender, Function_SameRace, Function_SameFaction, From 8de93db488dba3f9543c9a73a2824613d89e8f15 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Mar 2013 02:06:36 +0100 Subject: [PATCH 0757/1483] Coding style consistence --- apps/openmw/mwdialogue/selectwrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index d48a06323e..64bd1d2449 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -262,7 +262,7 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const { static const Function functions[] = { - Function_NotFaction, SelectWrapper::Function_NotClass, SelectWrapper::Function_NotRace, + Function_NotFaction, Function_NotClass, Function_NotRace, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcSkill, Function_PcExpelled, From 6783ff67483b5a227975f1ce76d35f3713e89caa Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Mar 2013 03:17:05 +0100 Subject: [PATCH 0758/1483] Workaround to have dialogues until actor detection is implemented for NPCs --- apps/openmw/mwworld/class.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 985d35d45e..108efddd81 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -169,7 +169,7 @@ namespace MWWorld bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const { - return false; + return true; } float Class::getArmorRating (const MWWorld::Ptr& ptr) const From cd84b68e4b58572cf0e896c83f4968ee41c65e55 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 20 Mar 2013 20:55:48 +0100 Subject: [PATCH 0759/1483] silencing some warnings --- apps/openmw/mwdialogue/filter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index c2d0515dd7..cd9908d3df 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -454,11 +454,11 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co std::string name = select.getName(); int i = 0; - for (; i < script->mVarNames.size(); ++i) + for (; i < static_cast (script->mVarNames.size()); ++i) if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name) break; - if (i >= script->mVarNames.size()) + if (i >= static_cast (script->mVarNames.size())) return true; // script does not have a variable of this name return false; From d05508db52c52f5a3973c387fe5e21864859e70d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 10:07:25 +0100 Subject: [PATCH 0760/1483] switching editor id tables from QAbstractTableModel to QAbstractItemModel (in preparation for record types like containers) --- apps/opencs/model/world/commands.cpp | 2 +- apps/opencs/model/world/data.cpp | 10 +++++----- apps/opencs/model/world/data.hpp | 10 +++++----- apps/opencs/model/world/idtable.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/idtable.hpp | 9 +++++++-- apps/opencs/view/world/dialoguesubview.cpp | 4 ++-- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index e22ecf9921..1f8660bdde 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -1,7 +1,7 @@ #include "commands.hpp" -#include +#include #include "idtableproxymodel.hpp" #include "idtable.hpp" diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index bbd8667b34..06e638b07f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include @@ -12,7 +12,7 @@ #include "idtable.hpp" #include "columns.hpp" -void CSMWorld::Data::addModel (QAbstractTableModel *model, UniversalId::Type type1, +void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1, UniversalId::Type type2) { mModels.push_back (model); @@ -42,7 +42,7 @@ CSMWorld::Data::Data() CSMWorld::Data::~Data() { - for (std::vector::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) + for (std::vector::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) delete *iter; } @@ -66,9 +66,9 @@ CSMWorld::IdCollection& CSMWorld::Data::getGmsts() return mGmsts; } -QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) +QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { - std::map::iterator iter = mModelIndex.find (id.getType()); + std::map::iterator iter = mModelIndex.find (id.getType()); if (iter==mModelIndex.end()) throw std::logic_error ("No table model available for " + id.toString()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 3745346511..e42d5c1026 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -12,7 +12,7 @@ #include "idcollection.hpp" #include "universalid.hpp" -class QAbstractTableModel; +class QAbstractItemModel; namespace CSMWorld { @@ -20,14 +20,14 @@ namespace CSMWorld { IdCollection mGlobals; IdCollection mGmsts; - std::vector mModels; - std::map mModelIndex; + std::vector mModels; + std::map mModelIndex; // not implemented Data (const Data&); Data& operator= (const Data&); - void addModel (QAbstractTableModel *model, UniversalId::Type type1, + void addModel (QAbstractItemModel *model, UniversalId::Type type1, UniversalId::Type type2 = UniversalId::Type_None); public: @@ -44,7 +44,7 @@ namespace CSMWorld IdCollection& getGmsts(); - QAbstractTableModel *getTableModel (const UniversalId& id); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// /// \note The returned table may either be the model for the ID itself or the model that diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index afed6b6eda..79e33584b2 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -96,6 +96,25 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren return true; } +QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const +{ + if (parent.isValid()) + return QModelIndex(); + + if (row<0 || row>=mIdCollection->getSize()) + return QModelIndex(); + + if (column<0 || column>=mIdCollection->getColumns()) + return QModelIndex(); + + return createIndex (row, column); +} + +QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const +{ + return QModelIndex(); +} + void CSMWorld::IdTable::addRecord (const std::string& id) { int index = mIdCollection->getSize(); diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index deaebaa38a..80476c5243 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -1,14 +1,14 @@ #ifndef CSM_WOLRD_IDTABLE_H #define CSM_WOLRD_IDTABLE_H -#include +#include namespace CSMWorld { class IdCollectionBase; class RecordBase; - class IdTable : public QAbstractTableModel + class IdTable : public QAbstractItemModel { Q_OBJECT @@ -39,6 +39,11 @@ namespace CSMWorld virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) + const; + + virtual QModelIndex parent (const QModelIndex& index) const; + void addRecord (const std::string& id); QModelIndex getModelIndex (const std::string& id, int column) const; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e16de99eff..cedb20de92 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -24,7 +24,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM widget->setLayout (layout); - QAbstractTableModel *model = document.getData().getTableModel (id); + QAbstractItemModel *model = document.getData().getTableModel (id); int columns = model->columnCount(); From 5346508471d6339bc251679fb284b56aaed5ca29 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 10:16:32 +0100 Subject: [PATCH 0761/1483] added kate junk to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 776e2b6591..27d3a13de3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ data CMakeLists.txt.user *.swp *.swo +*.kate-swp From ebb1dab8e12a593e8862ff75759c32597bac4316 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 10:19:07 +0100 Subject: [PATCH 0762/1483] removed debugging leftovers --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7a88335c89..c6b8bbc73d 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,7 +2,7 @@ #include "document.hpp" #include -#include + void CSMDoc::Document::load (const std::vector::const_iterator& begin, const std::vector::const_iterator& end, bool lastAsModified) { From cafbabde457172584c3e776b587a52975daec96a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 12:13:32 +0100 Subject: [PATCH 0763/1483] fixed broken loading of single files into the editor --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index c6b8bbc73d..47cf1f6642 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -214,7 +214,7 @@ CSMDoc::Document::Document (const std::vector& files, b if (new_ && files.size()==1) createBase(); - else if (files.size()>1) + else { std::vector::const_iterator end = files.end(); From 9464f45d57aacbb16455ff58755f4af46e8feb8b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 12:47:22 +0100 Subject: [PATCH 0764/1483] fixed an encoding problem. I hate you QString. I hate you so much --- apps/opencs/model/world/columns.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 018825831b..1492e96b7d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -35,7 +35,7 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mId.c_str(); + return QString::fromUtf8 (record.get().mId.c_str()); } virtual bool isEditable() const @@ -127,17 +127,17 @@ namespace CSMWorld { case ESM::VT_String: - return record.get().mValue.getString().c_str(); break; + return QString::fromUtf8 (record.get().mValue.getString().c_str()); case ESM::VT_Int: case ESM::VT_Short: case ESM::VT_Long: - return record.get().mValue.getInteger(); break; + return record.get().mValue.getInteger(); case ESM::VT_Float: - return record.get().mValue.getFloat(); break; + return record.get().mValue.getFloat(); default: return QVariant(); } From 1d1471b81c9b35f9faabdbbf575151491bf2701c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 12:57:10 +0100 Subject: [PATCH 0765/1483] fixed a bug in ESM::Variant::write (was affecting string values) --- components/esm/variant.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index d25072e548..a7859d1283 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -186,7 +186,7 @@ void ESM::Variant::write (std::ostream& stream) const case VT_String: - stream << "variant string: \"" << mData->getString() << "\2"; + stream << "variant string: \"" << mData->getString() << "\""; break; } } From a955068853b0a4aa83ff31df5dfc492f24fc6b1b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 13:40:55 +0100 Subject: [PATCH 0766/1483] added universal IDs for skills --- apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index c006852bc6..6fce376bea 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -19,6 +19,7 @@ namespace { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -27,6 +28,7 @@ namespace { { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 9ff7d17b18..a412cb6b1e 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -37,8 +37,9 @@ namespace CSMWorld Type_Global, Type_VerificationResults, Type_Gmsts, - Type_Gmst - + Type_Gmst, + Type_Skills, + Type_Skill }; private: From 947ab6635b3b7f038aea4ea233480bb12a2b3778 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 14:29:31 +0100 Subject: [PATCH 0767/1483] removed automatic detection of setting modified to the same value of base with subsequent setting modifiction state to base only (can cause problems with implicitly added records) --- apps/opencs/model/world/record.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 53bb7ea2ce..e442d0a391 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -81,9 +81,7 @@ namespace CSMWorld throw std::logic_error ("attempt to modify a deleted record"); mModified = modified; - - if (mState!=State_ModifiedOnly) - mState = mBase==mModified ? State_BaseOnly : State_Modified; + mState = State_Modified; } template From 7df0f6aaeed139d02262364ddcb9d777d0717e34 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 14:30:27 +0100 Subject: [PATCH 0768/1483] prepared skill record for use in editor --- components/esm/loadskil.cpp | 25 +++++++++++++++++++++++++ components/esm/loadskil.hpp | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index a4d21c5912..ac9fc27897 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -1,5 +1,7 @@ #include "loadskil.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" @@ -98,6 +100,22 @@ void Skill::load(ESMReader &esm) esm.getHNT(mIndex, "INDX"); esm.getHNT(mData, "SKDT", 24); mDescription = esm.getHNOString("DESC"); + + // create an ID from the index and the name (only used in the editor and likely to change in the + // future) + std::ostringstream stream; + + stream << "#"; + + if (mIndex<10) + stream << "0"; + + stream << mIndex; + + if (mIndex>=0 && mIndex Date: Thu, 21 Mar 2013 14:31:32 +0100 Subject: [PATCH 0769/1483] added basic support for skills to editor --- apps/opencs/model/world/data.cpp | 6 +++++- apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 1 + apps/opencs/view/world/subviews.cpp | 3 +++ 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 06e638b07f..6b0a83e74c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -36,8 +36,12 @@ CSMWorld::Data::Data() mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); + mSkills.addColumn (new StringIdColumn); + mSkills.addColumn (new RecordStateColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); + addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); } CSMWorld::Data::~Data() @@ -102,7 +106,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) { case ESM::REC_GLOB: mGlobals.load (reader, base); break; case ESM::REC_GMST: mGmsts.load (reader, base); break; - + case ESM::REC_SKIL: mSkills.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index e42d5c1026..dc9aee0618 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -8,6 +8,7 @@ #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -20,6 +21,7 @@ namespace CSMWorld { IdCollection mGlobals; IdCollection mGmsts; + IdCollection mSkills; std::vector mModels; std::map mModelIndex; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 995d3ca2e2..267ddf26cc 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -86,6 +86,10 @@ void CSVDoc::View::setupWorldMenu() connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView())); world->addAction (gmsts); + QAction *skills = new QAction (tr ("Skills"), this); + connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView())); + world->addAction (skills); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -244,6 +248,11 @@ void CSVDoc::View::addGmstsSubView() addSubView (CSMWorld::UniversalId::Type_Gmsts); } +void CSVDoc::View::addSkillsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Skills); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index e91a4d4a80..4c5aa40784 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -116,6 +116,7 @@ namespace CSVDoc void addGmstsSubView(); + void addSkillsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 351007ded5..bdff0017b4 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -14,6 +14,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Gmsts, new CSVDoc::SubViewFactoryWithCreateFlag (false)); + manager.add (CSMWorld::UniversalId::Type_Skills, + new CSVDoc::SubViewFactoryWithCreateFlag (false)); + manager.add (CSMWorld::UniversalId::Type_Global, new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file From 8e472cc62495c5a03a61f9661ae34d7a3369df94 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 14:38:06 +0100 Subject: [PATCH 0770/1483] added description column to skill table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 2 ++ 2 files changed, 27 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1492e96b7d..a84c9ddf64 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -177,6 +177,31 @@ namespace CSMWorld return true; } }; + + template + struct DescriptionColumn : public Column + { + DescriptionColumn() : Column ("Description", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mDescription.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mDescription = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 6b0a83e74c..51ea3e71be 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -39,6 +39,8 @@ CSMWorld::Data::Data() mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); From 3277ef26dab02aeca1668f0bf1be33cde8edb6e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 Mar 2013 21:08:23 +0100 Subject: [PATCH 0771/1483] Fix a crash when dropping objects without a collision shape --- libs/openengine/bullet/physic.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index c4947af1e1..8641996768 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -603,6 +603,14 @@ namespace Physic btTransform trans; trans.setIdentity(); - shape->mCollisionShape->getAabb(trans, min, max); + if (shape->mRaycastingShape) + shape->mRaycastingShape->getAabb(trans, min, max); + else if (shape->mCollisionShape) + shape->mCollisionShape->getAabb(trans, min, max); + else + { + min = btVector3(0,0,0); + max = btVector3(0,0,0); + } } }} From 918cdcffc200da31602d270fac2144d8220ad937 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 Mar 2013 05:50:54 +0100 Subject: [PATCH 0772/1483] Split up components/esm/loadlocks --- apps/esmtool/record.cpp | 8 +-- apps/esmtool/record.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 36 ++++++------- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwscript/compilercontext.cpp | 2 +- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 6 +-- apps/openmw/mwworld/containerstore.hpp | 6 +-- apps/openmw/mwworld/esmstore.hpp | 4 +- apps/openmw/mwworld/manualref.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/loadlock.cpp | 31 +++++++++++ components/esm/loadlock.hpp | 31 +++++++++++ components/esm/loadlocks.cpp | 65 ------------------------ components/esm/loadlocks.hpp | 56 -------------------- components/esm/loadprob.cpp | 30 +++++++++++ components/esm/loadprob.hpp | 31 +++++++++++ components/esm/loadrepa.cpp | 31 +++++++++++ components/esm/loadrepa.hpp | 31 +++++++++++ components/esm/records.hpp | 4 +- 26 files changed, 228 insertions(+), 166 deletions(-) create mode 100644 components/esm/loadlock.cpp create mode 100644 components/esm/loadlock.hpp delete mode 100644 components/esm/loadlocks.cpp delete mode 100644 components/esm/loadlocks.hpp create mode 100644 components/esm/loadprob.cpp create mode 100644 components/esm/loadprob.hpp create mode 100644 components/esm/loadrepa.cpp create mode 100644 components/esm/loadrepa.hpp diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 38fddd6b92..de3a175106 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -275,7 +275,7 @@ RecordBase::create(ESM::NAME type) } case ESM::REC_LOCK: { - record = new EsmTool::Record; + record = new EsmTool::Record; break; } case ESM::REC_LTEX: @@ -864,14 +864,13 @@ void Record::print() } template<> -void Record::print() +void Record::print() { std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -886,8 +885,6 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - // BUG? No Type Label? - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -902,7 +899,6 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index c3daa9d0c3..e0dd988a65 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -104,7 +104,7 @@ namespace EsmTool template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); - template<> void Record::print(); + template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 665644736d..6fa8f55520 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -1,7 +1,7 @@ #include "lockpick.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -41,8 +41,8 @@ namespace MWClass std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); assert(ref->mBase != NULL); const std::string &model = ref->mBase->mModel; @@ -54,8 +54,8 @@ namespace MWClass std::string Lockpick::getName (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mName; } @@ -75,8 +75,8 @@ namespace MWClass std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mScript; } @@ -92,8 +92,8 @@ namespace MWClass int Lockpick::getValue (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mData.mValue; } @@ -102,7 +102,7 @@ namespace MWClass { boost::shared_ptr instance (new Lockpick); - registerClass (typeid (ESM::Tool).name(), instance); + registerClass (typeid (ESM::Lockpick).name(), instance); } std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr) const @@ -117,24 +117,24 @@ namespace MWClass std::string Lockpick::getInventoryIcon (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mIcon; } bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -171,8 +171,8 @@ namespace MWClass MWWorld::Ptr Lockpick::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return MWWorld::Ptr(&cell.mLockpicks.insert(*ref), &cell); } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 5b1b55bd31..68d9b49c30 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -1,7 +1,7 @@ #include "probe.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index d6afe93198..8a13aa2078 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -1,7 +1,7 @@ #include "repair.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index e476865433..9c1fbae69e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -45,7 +45,7 @@ namespace mapping.push_back( typeid(ESM::Book).name() ); mapping.push_back( typeid(ESM::Light).name() ); mapping.push_back( typeid(ESM::Miscellaneous).name() ); - mapping.push_back( typeid(ESM::Tool).name() ); + mapping.push_back( typeid(ESM::Lockpick).name() ); mapping.push_back( typeid(ESM::Repair).name() ); mapping.push_back( typeid(ESM::Probe).name() ); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 29966bd08a..578ec3da3e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -308,7 +308,7 @@ namespace MWGui && (type != typeid(ESM::Ingredient).name()) && (type != typeid(ESM::Light).name()) && (type != typeid(ESM::Miscellaneous).name()) - && (type != typeid(ESM::Tool).name()) + && (type != typeid(ESM::Lockpick).name()) && (type != typeid(ESM::Probe).name()) && (type != typeid(ESM::Repair).name()) && (type != typeid(ESM::Weapon).name()) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0fd24601a8..f84a0abc88 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -368,7 +368,7 @@ namespace MWGui return services & ESM::NPC::Books; else if (item.getTypeName() == typeid(ESM::Ingredient).name()) return services & ESM::NPC::Ingredients; - else if (item.getTypeName() == typeid(ESM::Tool).name()) + else if (item.getTypeName() == typeid(ESM::Lockpick).name()) return services & ESM::NPC::Picks; else if (item.getTypeName() == typeid(ESM::Probe).name()) return services & ESM::NPC::Probes; diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 57d93512f4..7e63a33b25 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -59,7 +59,7 @@ namespace MWScript store.get().search (name) || store.get().search (name) || store.get().search (name) || - store.get().search (name) || + store.get().search (name) || store.get().search (name) || store.get().search (name) || store.get().search (name) || diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index f95d30df13..5f771be475 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -206,7 +206,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce if (MWWorld::LiveCellRef *ref = cell.mLights.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.mLockpicks.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mLockpicks.find (name)) ptr = Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = cell.mMiscItems.find (name)) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index c182f196bc..2e6b45bb7e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -112,7 +112,7 @@ namespace MWWorld CellRefList mCreatureLists; CellRefList mItemLists; CellRefList mLights; - CellRefList mLockpicks; + CellRefList mLockpicks; CellRefList mMiscItems; CellRefList mNpcs; CellRefList mProbes; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8a7884e9e0..3dce049f4d 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -171,7 +171,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr case Type_Clothing: clothes.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --clothes.mList.end()); break; case Type_Ingredient: ingreds.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --ingreds.mList.end()); break; case Type_Light: lights.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lights.mList.end()); break; - case Type_Lockpick: lockpicks.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break; + case Type_Lockpick: lockpicks.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break; case Type_Miscellaneous: miscItems.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --miscItems.mList.end()); break; case Type_Probe: probes.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --probes.mList.end()); break; case Type_Repair: repairs.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --repairs.mList.end()); break; @@ -272,7 +272,7 @@ int MWWorld::ContainerStore::getType (const Ptr& ptr) if (ptr.getTypeName()==typeid (ESM::Light).name()) return Type_Light; - if (ptr.getTypeName()==typeid (ESM::Tool).name()) + if (ptr.getTypeName()==typeid (ESM::Lockpick).name()) return Type_Lockpick; if (ptr.getTypeName()==typeid (ESM::Miscellaneous).name()) @@ -321,7 +321,7 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *contain : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e4f75d5478..9d315d27f0 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -44,7 +44,7 @@ namespace MWWorld MWWorld::CellRefList clothes; MWWorld::CellRefList ingreds; MWWorld::CellRefList lights; - MWWorld::CellRefList lockpicks; + MWWorld::CellRefList lockpicks; MWWorld::CellRefList miscItems; MWWorld::CellRefList probes; MWWorld::CellRefList repairs; @@ -127,7 +127,7 @@ namespace MWWorld MWWorld::CellRefList::List::iterator mClothing; MWWorld::CellRefList::List::iterator mIngredient; MWWorld::CellRefList::List::iterator mLight; - MWWorld::CellRefList::List::iterator mLockpick; + MWWorld::CellRefList::List::iterator mLockpick; MWWorld::CellRefList::List::iterator mMiscellaneous; MWWorld::CellRefList::List::iterator mProbe; MWWorld::CellRefList::List::iterator mRepair; @@ -149,7 +149,7 @@ namespace MWWorld ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index b9b95e4f4e..61a106e163 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -32,7 +32,7 @@ namespace MWWorld Store mCreatureLists; Store mItemLists; Store mLights; - Store mLockpicks; + Store mLockpicks; Store mMiscItems; Store mNpcs; Store mNpcChange; @@ -312,7 +312,7 @@ namespace MWWorld } template <> - inline const Store &ESMStore::get() const { + inline const Store &ESMStore::get() const { return mLockpicks; } diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 91b8cf8cd4..466341b953 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -53,7 +53,7 @@ namespace MWWorld !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && - !create (store.get(), name) && + !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1b5dc3bd35..5d6863c029 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -101,7 +101,7 @@ namespace MWWorld return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLights)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLockpicks)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLockpicks)) return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mMiscItems)) return Ptr (ref, &cell); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f7b97056cb..88bf764445 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (file_finder add_component_dir (esm attr defs esmcommon esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst - loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc + loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 ) diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp new file mode 100644 index 0000000000..02a36abfe6 --- /dev/null +++ b/components/esm/loadlock.cpp @@ -0,0 +1,31 @@ +#include "loadlock.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Lockpick::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "LKDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Lockpick::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("LKDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + + +} diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp new file mode 100644 index 0000000000..0bbedf362f --- /dev/null +++ b/components/esm/loadlock.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_LOCK_H +#define OPENMW_ESM_LOCK_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Lockpick +{ + struct Data + { + float mWeight; + int mValue; + + float mQuality; + int mUses; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/loadlocks.cpp b/components/esm/loadlocks.cpp deleted file mode 100644 index 057da595e7..0000000000 --- a/components/esm/loadlocks.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "loadlocks.hpp" - -#include "esmreader.hpp" -#include "esmwriter.hpp" - -namespace ESM -{ - -void Tool::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); - - esm.getSubName(); - NAME n = esm.retSubName(); - // The data name varies, RIDT for repair items, LKDT for lock - // picks, PBDT for probes - - esm.getHT(mData, 16); - - if (n == "RIDT") - { - mType = Type_Repair; - // Swap t.data.quality and t.data.uses for repair items (sigh) - float tmp = *((float*) &mData.mUses); - mData.mUses = *((int*) &mData.mQuality); - mData.mQuality = tmp; - } - else if (n == "LKDT") - mType = Type_Pick; - else if (n == "PBDT") - mType = Type_Probe; - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} - -void Tool::save(ESMWriter &esm) -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNCString("FNAM", mName); - - std::string typeName; - switch(mType) - { - case Type_Repair: typeName = "RIDT"; break; - case Type_Pick: typeName = "LKDT"; break; - case Type_Probe: typeName = "PBDT"; break; - } - - Data write = mData; - if (mType == Type_Repair) - { - float tmp = *((float*) &write.mUses); - write.mUses = *((int*) &write.mQuality); - write.mQuality = tmp; - } - - esm.writeHNT(typeName, write, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} - - -} diff --git a/components/esm/loadlocks.hpp b/components/esm/loadlocks.hpp deleted file mode 100644 index 8e88c548e7..0000000000 --- a/components/esm/loadlocks.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef OPENMW_ESM_LOCKS_H -#define OPENMW_ESM_LOCKS_H - -#include - -namespace ESM -{ - -class ESMReader; -class ESMWriter; - -/* - * This file covers lockpicks (LOCK), probes (PROB) and armor repair - * items (REPA). These have nearly identical data structures. - */ - -struct Tool -{ - enum Type - { - Type_Pick, - Type_Probe, - Type_Repair - }; - - struct Data - { - float mWeight; - int mValue; - - float mQuality; // And when I say nearly identical structure, I - int mUses; // mean perfectly identical except that these two - // variables are swaped for repair items. Don't ask - // me why. - }; // Size = 16 - - Data mData; - Type mType; - std::string mId, mName, mModel, mIcon, mScript; - - void load(ESMReader &esm); - void save(ESMWriter &esm); -}; - -struct Probe: Tool -{ - Probe() { mType = Type_Probe; } -}; - -struct Repair: Tool -{ - Repair() { mType = Type_Repair; } -}; - -} -#endif diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp new file mode 100644 index 0000000000..bbaec1ce2d --- /dev/null +++ b/components/esm/loadprob.cpp @@ -0,0 +1,30 @@ +#include "loadprob.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Probe::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "PBDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Probe::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("PBDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + +} diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp new file mode 100644 index 0000000000..4a47a86005 --- /dev/null +++ b/components/esm/loadprob.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_PROBE_H +#define OPENMW_ESM_PROBE_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Probe +{ + struct Data + { + float mWeight; + int mValue; + + float mQuality; + int mUses; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp new file mode 100644 index 0000000000..f7eeddf961 --- /dev/null +++ b/components/esm/loadrepa.cpp @@ -0,0 +1,31 @@ +#include "loadrepa.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Repair::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "RIDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Repair::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("RIDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + + +} diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp new file mode 100644 index 0000000000..60ff5df905 --- /dev/null +++ b/components/esm/loadrepa.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_REPA_H +#define OPENMW_ESM_REPA_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Repair +{ + struct Data + { + float mWeight; + int mValue; + + int mUses; + float mQuality; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/records.hpp b/components/esm/records.hpp index 0662c797c1..7a0452eb3f 100644 --- a/components/esm/records.hpp +++ b/components/esm/records.hpp @@ -26,7 +26,9 @@ #include "loadland.hpp" #include "loadlevlist.hpp" #include "loadligh.hpp" -#include "loadlocks.hpp" +#include "loadlock.hpp" +#include "loadrepa.hpp" +#include "loadprob.hpp" #include "loadltex.hpp" #include "loadmgef.hpp" #include "loadmisc.hpp" From feaf2b43fbfc7f3c2b3e6b7af859db1dc45b6d4d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 22 Mar 2013 09:44:59 +0100 Subject: [PATCH 0773/1483] disabled and deleted objects where not correctly ignored during adding objects to a cell when it became active --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 592fb5c80a..339026ca60 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -41,7 +41,7 @@ namespace ++current; - if (it->mData.getCount() || it->mData.isEnabled()) + if (it->mData.getCount() && it->mData.isEnabled()) { MWWorld::Ptr ptr (&*it, &cell); From 8e2f9f5186b6a969c8d73c255bdac7a28cef5ebe Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 Mar 2013 12:24:09 +0100 Subject: [PATCH 0774/1483] Fix CellRef to load current weapon/armor health correctly, also show it in the tooltips --- apps/esmtool/esmtool.cpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 +++-- apps/openmw/mwclass/lockpick.cpp | 4 ++-- apps/openmw/mwclass/probe.cpp | 4 ++-- apps/openmw/mwclass/repair.cpp | 4 ++-- apps/openmw/mwclass/weapon.cpp | 7 +++++-- apps/openmw/mwworld/manualref.hpp | 3 +-- components/esm/loadcell.cpp | 17 +++++------------ components/esm/loadcell.hpp | 12 ++++-------- 9 files changed, 25 insertions(+), 33 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 20c01af259..521383f3ff 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -227,7 +227,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Refnum: " << ref.mRefnum << std::endl; std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n"; - std::cout << " INTV: " << ref.mIntv << " NAM9: " << ref.mIntv << std::endl; + std::cout << " Uses/health: " << ref.mCharge << " NAM9: " << ref.mNam9 << std::endl; } } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index fdf211c28a..513ebf75fc 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -247,8 +247,9 @@ namespace MWClass text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); - /// \todo store the current armor health somewhere - text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + int remainingHealth = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mHealth; + text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")"; text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 6fa8f55520..2015726968 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -142,9 +142,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 68d9b49c30..e4533af655 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -141,9 +141,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 8a13aa2078..f0b6fe88d9 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -131,9 +131,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 475c08ccbf..e9e42d3fdd 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -334,9 +334,12 @@ namespace MWClass } } - /// \todo store the current weapon health somewhere if (ref->mBase->mData.mType < 11) // thrown weapons and arrows/bolts don't have health, only quantity - text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + { + int remainingHealth = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mHealth; + text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + } text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 466341b953..58395d8798 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -68,8 +68,7 @@ namespace MWWorld cellRef.mRefnum = -1; cellRef.mScale = 1; cellRef.mFactIndex = 0; - cellRef.mCharge = 0; - cellRef.mIntv = 0; + cellRef.mCharge = -1; cellRef.mNam9 = 0; cellRef.mTeleport = false; cellRef.mLockLevel = 0; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index da60f76af8..0731a8ff80 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -14,7 +14,7 @@ namespace ESM { -/// Some overloaded copare operators. +/// Some overloaded compare operators. bool operator==(const MovedCellRef& ref, int pRefnum) { return (ref.mRefnum == pRefnum); @@ -43,13 +43,9 @@ void CellRef::save(ESMWriter &esm) esm.writeHNT("INDX", mFactIndex); } - if (mCharge != -1.0) { - esm.writeHNT("XCHG", mCharge); - } + if (mCharge != -1) + esm.writeHNT("INTV", mCharge); - if (mIntv != -1) { - esm.writeHNT("INTV", mIntv); - } if (mNam9 != 0) { esm.writeHNT("NAM9", mNam9); } @@ -285,12 +281,9 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mFactIndex = -2; esm.getHNOT(ref.mFactIndex, "INDX"); - ref.mCharge = -1.0; - esm.getHNOT(ref.mCharge, "XCHG"); - - ref.mIntv = -1; ref.mNam9 = 0; - esm.getHNOT(ref.mIntv, "INTV"); + ref.mCharge = -1; + esm.getHNOT(ref.mCharge, "INTV"); esm.getHNOT(ref.mNam9, "NAM9"); // Present for doors that teleport you to another cell. diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 7db6dbe77c..97aa86ba0f 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -52,15 +52,11 @@ public: // is -1, which I assume means "any rank". int mFactIndex; - // Depends on context - possibly weapon health, number of uses left - // or weapon magic charge? - float mCharge; + // For weapon or armor, this is the remaining item health. + // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + int mCharge; - // I have no idea, these are present some times, often along with - // owner (ANAM) and sometimes otherwise. They are often (but not - // always) 1. INTV is big for lights (possibly a float?), might have - // something to do with remaining light "charge". - int mIntv, mNam9; + int mNam9; // For doors - true if this door teleports to somewhere else, false // if it should open through animation. From 20774f8f8178ad6a4ee9aea47da09ae0f7b075b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 Mar 2013 14:13:10 +0100 Subject: [PATCH 0775/1483] Added merchant repair feature --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 + apps/openmw/mwgui/dialogue.cpp | 8 ++ apps/openmw/mwgui/dialogue.hpp | 3 +- apps/openmw/mwgui/merchantrepair.cpp | 132 ++++++++++++++++++ apps/openmw/mwgui/merchantrepair.hpp | 37 +++++ apps/openmw/mwgui/mode.hpp | 2 + apps/openmw/mwgui/spellbuyingwindow.cpp | 11 -- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 - apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 4 + apps/openmw/mwworld/containerstore.cpp | 4 +- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_merchantrepair.layout | 33 +++++ files/mygui/openmw_spell_buying_window.layout | 10 +- 16 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 apps/openmw/mwgui/merchantrepair.cpp create mode 100644 apps/openmw/mwgui/merchantrepair.hpp create mode 100644 files/mygui/openmw_merchantrepair.layout diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0edc18afba..11c6360e57 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,6 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons + merchantrepair ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index cd28bb47e7..0a6de5e14d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -238,6 +238,7 @@ namespace MWBase virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; + virtual void startRepair(MWWorld::Ptr actor) = 0; virtual void changePointer (const std::string& name) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1628199950..b75c514a29 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -367,6 +367,9 @@ namespace MWDialogue if (services & ESM::NPC::Enchanting) windowServices |= MWGui::DialogueWindow::Service_Enchant; + if (services & ESM::NPC::Repair) + windowServices |= MWGui::DialogueWindow::Service_Repair; + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->setServices (windowServices); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0bbf7c7af4..9a7e51874f 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -280,6 +280,11 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) mWindowManager.pushGuiMode(GM_Training); mWindowManager.startTraining (mPtr); } + else if (topic == gmst.find("sRepair")->getString()) + { + mWindowManager.pushGuiMode(GM_MerchantRepair); + mWindowManager.startRepair (mPtr); + } } } } @@ -327,6 +332,9 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); + if (mServices & Service_Repair) + mTopicsList->addItem(gmst.find("sRepair")->getString()); + if (anyService || mPtr.getTypeName() == typeid(ESM::NPC).name()) mTopicsList->addSeparator(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a8e0a6d174..187731fc77 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -81,7 +81,8 @@ namespace MWGui Service_CreateSpells = 0x04, Service_Enchant = 0x08, Service_Training = 0x10, - Service_Travel = 0x20 + Service_Travel = 0x20, + Service_Repair = 0x40 }; protected: diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp new file mode 100644 index 0000000000..0a65326050 --- /dev/null +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -0,0 +1,132 @@ +#include "merchantrepair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "list.hpp" +#include "inventorywindow.hpp" +#include "tradewindow.hpp" + +namespace MWGui +{ + +MerchantRepair::MerchantRepair(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_merchantrepair.layout", parWindowManager) +{ + getWidget(mList, "RepairView"); + getWidget(mOkButton, "OkButton"); + getWidget(mGoldLabel, "PlayerGold"); + + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onOkButtonClick); +} + +void MerchantRepair::startRepair(const MWWorld::Ptr &actor) +{ + mActor = actor; + + while (mList->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mList->getChildAt(0)); + + int currentY = 0; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + for (MWWorld::ContainerStoreIterator iter (store.begin()); + iter!=store.end(); ++iter) + { + if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) + { + int maxDurability = MWWorld::Class::get(*iter).getItemMaxHealth(*iter); + int durability = (iter->getCellRef().mCharge == -1) ? maxDurability : iter->getCellRef().mCharge; + if (maxDurability == durability) + continue; + + int basePrice = MWWorld::Class::get(*iter).getValue(*iter); + float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fRepairMult")->getFloat(); + + float p = std::max(1, basePrice); + float r = std::max(1, static_cast(maxDurability / p)); + + int x = ((maxDurability - durability) / r); + x = (fRepairMult * x); + + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); + + + std::string name = MWWorld::Class::get(*iter).getName(*iter) + + " - " + boost::lexical_cast(price) + + MWBase::Environment::get().getWorld()->getStore().get() + .find("sgp")->getString();; + + + MyGUI::Button* button = + mList->createWidget( + (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + 0, + currentY, + 0, + 18, + MyGUI::Align::Default + ); + + currentY += 18; + + button->setEnabled(price<=mWindowManager.getInventoryWindow()->getPlayerGold()); + button->setUserString("Price", boost::lexical_cast(price)); + button->setUserData(*iter); + button->setCaptionWithReplacing(name); + button->setSize(button->getTextSize().width,18); + button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); + button->setUserString("ToolTipType", "ItemPtr"); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); + } + } + mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY))); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); +} + +void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mList->getViewOffset().top + _rel*0.3 > 0) + mList->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mList->setViewOffset(MyGUI::IntPoint(0, mList->getViewOffset().top + _rel*0.3)); +} + +void MerchantRepair::open() +{ + center(); +} + +void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) +{ + // repair + MWWorld::Ptr item = *sender->getUserData(); + item.getCellRef().mCharge = MWWorld::Class::get(item).getItemMaxHealth(item); + + MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); + + int price = boost::lexical_cast(sender->getUserString("Price")); + mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + + startRepair(mActor); +} + +void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) +{ + mWindowManager.removeGuiMode(GM_MerchantRepair); +} + +} diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp new file mode 100644 index 0000000000..4b7e2b8fbd --- /dev/null +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -0,0 +1,37 @@ +#ifndef OPENMW_MWGUI_MERCHANTREPAIR_H +#define OPENMW_MWGUI_MERCHANTREPAIR_H + +#include "window_base.hpp" +#include "../mwworld/ptr.hpp" + + + +namespace MWGui +{ + +class MerchantRepair : public WindowBase +{ +public: + MerchantRepair(MWBase::WindowManager &parWindowManager); + + virtual void open(); + + void startRepair(const MWWorld::Ptr& actor); + +private: + MyGUI::ScrollView* mList; + MyGUI::Button* mOkButton; + MyGUI::TextBox* mGoldLabel; + + MWWorld::Ptr mActor; + +protected: + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onRepairButtonClick(MyGUI::Widget* sender); + void onOkButtonClick(MyGUI::Widget* sender); + +}; + +} + +#endif diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 3195372978..4091f47acc 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -16,6 +16,7 @@ namespace MWGui GM_Scroll, // Read scroll GM_Book, // Read book GM_Alchemy, // Make potions + GM_Repair, GM_Dialogue, // NPC interaction GM_Barter, @@ -26,6 +27,7 @@ namespace MWGui GM_SpellCreation, GM_Enchanting, GM_Training, + GM_MerchantRepair, GM_Levelup, diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 40fcf2988a..d39ad6a5ae 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -32,20 +32,9 @@ namespace MWGui getWidget(mCancelButton, "CancelButton"); getWidget(mPlayerGold, "PlayerGold"); - getWidget(mSelect, "Select"); - getWidget(mSpells, "Spells"); getWidget(mSpellsView, "SpellsView"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); - - mSpells->setCoord(450/2-mSpells->getTextSize().width/2, - mSpells->getTop(), - mSpells->getTextSize().width, - mSpells->getHeight()); - mSelect->setCoord(8, - mSelect->getTop(), - mSelect->getTextSize().width, - mSelect->getHeight()); } void SpellBuyingWindow::addSpell(const std::string& spellId) diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index c4988fff35..f9cda35df0 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,8 +28,6 @@ namespace MWGui protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - MyGUI::TextBox* mSpells; - MyGUI::TextBox* mSelect; MyGUI::ScrollView* mSpellsView; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b7d6ed1c9b..07ea726206 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -55,6 +55,7 @@ #include "exposedwindow.hpp" #include "cursor.hpp" #include "spellicons.hpp" +#include "merchantrepair.hpp" using namespace MWGui; @@ -90,6 +91,7 @@ WindowManager::WindowManager( , mSpellCreationDialog(NULL) , mEnchantingDialog(NULL) , mTrainingWindow(NULL) + , mMerchantRepair(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -180,6 +182,7 @@ WindowManager::WindowManager( mSpellCreationDialog = new SpellCreationDialog(*this); mEnchantingDialog = new EnchantingDialog(*this); mTrainingWindow = new TrainingWindow(*this); + mMerchantRepair = new MerchantRepair(*this); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -245,6 +248,7 @@ WindowManager::~WindowManager() delete mTrainingWindow; delete mCountDialog; delete mQuickKeysMenu; + delete mMerchantRepair; delete mCursor; cleanupGarbage(); @@ -303,6 +307,7 @@ void WindowManager::updateVisible() mSpellCreationDialog->setVisible(false); mEnchantingDialog->setVisible(false); mTrainingWindow->setVisible(false); + mMerchantRepair->setVisible(false); mHud->setVisible(mHudEnabled); @@ -428,6 +433,9 @@ void WindowManager::updateVisible() case GM_Training: mTrainingWindow->setVisible(true); break; + case GM_MerchantRepair: + mMerchantRepair->setVisible(true); + break; case GM_InterMessageBox: break; case GM_Journal: @@ -1132,6 +1140,11 @@ void WindowManager::startTraining(MWWorld::Ptr actor) mTrainingWindow->startTraining(actor); } +void WindowManager::startRepair(MWWorld::Ptr actor) +{ + mMerchantRepair->startRepair(actor); +} + const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a7baf5207e..2242a8467b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -74,6 +74,7 @@ namespace MWGui class TrainingWindow; class Cursor; class SpellIcons; + class MerchantRepair; class WindowManager : public MWBase::WindowManager { @@ -229,6 +230,7 @@ namespace MWGui virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor); virtual void startTraining(MWWorld::Ptr actor); + virtual void startRepair(MWWorld::Ptr actor); virtual void changePointer (const std::string& name); @@ -266,6 +268,8 @@ namespace MWGui SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; + MerchantRepair* mMerchantRepair; + Translation::Storage& mTranslationDataStorage; Cursor* mCursor; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 3dce049f4d..223514e086 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -62,13 +62,13 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { - /// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented + /// \todo add current enchantment charge here when it is implemented if ( ptr1.mCellRef->mRefID == ptr2.mCellRef->mRefID && MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks && MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier) && ptr1.mCellRef->mOwner == ptr2.mCellRef->mOwner && ptr1.mCellRef->mSoul == ptr2.mCellRef->mSoul - && ptr1.mCellRef->mCharge == ptr2.mCellRef->mCharge) + && ptr1.mCellRef->mCharge == -1) // item that is already partly used up never stacks return true; return false; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index beace5b81e..4adebf1dfd 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -78,6 +78,7 @@ set(MYGUI_FILES openmw_trainingwindow.layout openmw_travel_window.layout openmw_persuasion_dialog.layout + openmw_merchantrepair.layout smallbars.png DejaVuLGCSansMono.ttf markers.png diff --git a/files/mygui/openmw_merchantrepair.layout b/files/mygui/openmw_merchantrepair.layout new file mode 100644 index 0000000000..360f5f4f09 --- /dev/null +++ b/files/mygui/openmw_merchantrepair.layout @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_spell_buying_window.layout b/files/mygui/openmw_spell_buying_window.layout index 1e18fda236..c55cd0e22d 100644 --- a/files/mygui/openmw_spell_buying_window.layout +++ b/files/mygui/openmw_spell_buying_window.layout @@ -5,13 +5,13 @@ - - + + - - - + + + From 78f3f19f62393d5d256657b8aa8c60e1eb94058a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 Mar 2013 14:28:50 +0100 Subject: [PATCH 0776/1483] Thrown weapons, arrows and bolts shouldn't have item health --- apps/openmw/mwclass/weapon.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index e9e42d3fdd..a6a8e631b3 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -75,7 +75,10 @@ namespace MWClass bool Weapon::hasItemHealth (const MWWorld::Ptr& ptr) const { - return true; + MWWorld::LiveCellRef *ref = + ptr.get(); + + return (ref->mBase->mData.mType < 11); // thrown weapons and arrows/bolts don't have health, only quantity } int Weapon::getItemMaxHealth (const MWWorld::Ptr& ptr) const From a2ca679beb294140710a5dd1b0e2b273405db8a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Mar 2013 08:16:46 +0100 Subject: [PATCH 0777/1483] Added PC repair feature --- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwclass/repair.cpp | 19 +++ apps/openmw/mwclass/repair.hpp | 12 ++ apps/openmw/mwgui/repair.cpp | 157 +++++++++++++++++++++++++ apps/openmw/mwgui/repair.hpp | 46 ++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 + apps/openmw/mwmechanics/repair.cpp | 110 +++++++++++++++++ apps/openmw/mwmechanics/repair.hpp | 23 ++++ apps/openmw/mwworld/actionrepair.cpp | 18 +++ apps/openmw/mwworld/actionrepair.hpp | 17 +++ apps/openmw/mwworld/containerstore.cpp | 24 ++-- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_repair.layout | 33 ++++++ files/mygui/openmw_text.skin.xml | 4 +- 16 files changed, 469 insertions(+), 18 deletions(-) create mode 100644 apps/openmw/mwgui/repair.cpp create mode 100644 apps/openmw/mwgui/repair.hpp create mode 100644 apps/openmw/mwmechanics/repair.cpp create mode 100644 apps/openmw/mwmechanics/repair.hpp create mode 100644 apps/openmw/mwworld/actionrepair.cpp create mode 100644 apps/openmw/mwworld/actionrepair.hpp create mode 100644 files/mygui/openmw_repair.layout diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 11c6360e57..41599b35db 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair + merchantrepair repair ) add_openmw_dir (mwdialogue @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback + esmstore store recordcmp fallback actionrepair ) add_openmw_dir (mwclass @@ -65,7 +65,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate + aiescort aiactivate repair ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 0a6de5e14d..6760c89d07 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -239,6 +239,7 @@ namespace MWBase virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; virtual void startRepair(MWWorld::Ptr actor) = 0; + virtual void startRepairItem(MWWorld::Ptr item) = 0; virtual void changePointer (const std::string& name) = 0; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index f0b6fe88d9..bafedee88b 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -12,6 +12,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/actionrepair.hpp" #include "../mwgui/tooltips.hpp" @@ -120,6 +121,19 @@ namespace MWClass return (ref->mBase->mName != ""); } + bool Repair::hasItemHealth (const MWWorld::Ptr& ptr) const + { + return true; + } + + int Repair::getItemMaxHealth (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mUses; + } + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -156,4 +170,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mRepairs.insert(*ref), &cell); } + + boost::shared_ptr Repair::use (const MWWorld::Ptr& ptr) const + { + return boost::shared_ptr(new MWWorld::ActionRepair(ptr)); + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index c58e38f96b..3083c97e35 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -49,6 +49,18 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu (default implementation: return a + /// null action). + + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + ///< \return Item health data available? (default implementation: false) + + virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + ///< Return item max health or throw an exception, if class does not have item health + /// (default implementation: throw an exceoption) }; } diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp new file mode 100644 index 0000000000..f53ddc4305 --- /dev/null +++ b/apps/openmw/mwgui/repair.cpp @@ -0,0 +1,157 @@ +#include "repair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "widgets.hpp" + +namespace MWGui +{ + +Repair::Repair(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_repair.layout", parWindowManager) +{ + getWidget(mRepairBox, "RepairBox"); + getWidget(mRepairView, "RepairView"); + getWidget(mToolBox, "ToolBox"); + getWidget(mToolIcon, "ToolIcon"); + getWidget(mUsesLabel, "UsesLabel"); + getWidget(mQualityLabel, "QualityLabel"); + getWidget(mCancelButton, "CancelButton"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel); +} + +void Repair::open() +{ + center(); +} + +void Repair::startRepairItem(const MWWorld::Ptr &item) +{ + mRepair.setTool(item); + + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(item).getInventoryIcon(item); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + mToolIcon->setImageTexture (path); + mToolIcon->setUserString("ToolTipType", "ItemPtr"); + mToolIcon->setUserData(item); + + updateRepairView(); +} + +void Repair::updateRepairView() +{ + MWWorld::LiveCellRef *ref = + mRepair.getTool().get(); + + int uses = (mRepair.getTool().getCellRef().mCharge != -1) ? mRepair.getTool().getCellRef().mCharge : ref->mBase->mData.mUses; + + float quality = ref->mBase->mData.mQuality; + + std::stringstream qualityStr; + qualityStr << std::setprecision(3) << quality; + + mUsesLabel->setCaptionWithReplacing("#{sUses} " + boost::lexical_cast(uses)); + mQualityLabel->setCaptionWithReplacing("#{sQuality} " + qualityStr.str()); + + bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0); + mToolBox->setVisible(toolBoxVisible); + + bool toolBoxWasVisible = (mRepairBox->getPosition().top != mToolBox->getPosition().top); + + if (toolBoxVisible && !toolBoxWasVisible) + { + // shrink + mRepairBox->setPosition(mRepairBox->getPosition() + MyGUI::IntPoint(0,mToolBox->getSize().height)); + mRepairBox->setSize(mRepairBox->getSize() - MyGUI::IntSize(0,mToolBox->getSize().height)); + } + else if (!toolBoxVisible && toolBoxWasVisible) + { + // expand + mRepairBox->setPosition(MyGUI::IntPoint (mRepairBox->getPosition().left, mToolBox->getPosition().top)); + mRepairBox->setSize(mRepairBox->getSize() + MyGUI::IntSize(0,mToolBox->getSize().height)); + } + + while (mRepairView->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mRepairView->getChildAt(0)); + + int currentY = 0; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; + for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); + iter!=store.end(); ++iter) + { + if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) + { + int maxDurability = MWWorld::Class::get(*iter).getItemMaxHealth(*iter); + int durability = (iter->getCellRef().mCharge == -1) ? maxDurability : iter->getCellRef().mCharge; + if (maxDurability == durability) + continue; + + MyGUI::TextBox* text = mRepairView->createWidget ( + "SandText", MyGUI::IntCoord(8, currentY, mRepairView->getWidth()-8, 18), MyGUI::Align::Default); + text->setCaption(MWWorld::Class::get(*iter).getName(*iter)); + text->setNeedMouseFocus(false); + currentY += 19; + + MyGUI::ImageBox* icon = mRepairView->createWidget ( + "ImageBox", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + icon->setImageTexture (path); + icon->setUserString("ToolTipType", "ItemPtr"); + icon->setUserData(*iter); + icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); + icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel); + + Widgets::MWDynamicStatPtr chargeWidget = mRepairView->createWidget + ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); + chargeWidget->setValue(durability, maxDurability); + chargeWidget->setNeedMouseFocus(false); + + currentY += 32 + 4; + } + } + mRepairView->setCanvasSize (MyGUI::IntSize(mRepairView->getWidth(), std::max(mRepairView->getHeight(), currentY))); +} + +void Repair::onCancel(MyGUI::Widget *sender) +{ + mWindowManager.removeGuiMode(GM_Repair); +} + +void Repair::onRepairItem(MyGUI::Widget *sender) +{ + if (!mRepair.getTool().getRefData().getCount()) + return; + + mRepair.repair(*sender->getUserData()); + + updateRepairView(); +} + +void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mRepairView->getViewOffset().top + _rel*0.3 > 0) + mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mRepairView->setViewOffset(MyGUI::IntPoint(0, mRepairView->getViewOffset().top + _rel*0.3)); +} + +} diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp new file mode 100644 index 0000000000..c14b1955bd --- /dev/null +++ b/apps/openmw/mwgui/repair.hpp @@ -0,0 +1,46 @@ +#ifndef OPENMW_MWGUI_REPAIR_H +#define OPENMW_MWGUI_REPAIR_H + +#include "window_base.hpp" + +#include "../mwworld/ptr.hpp" +#include "../mwmechanics/repair.hpp" + +namespace MWGui +{ + +class Repair : public WindowBase +{ +public: + Repair(MWBase::WindowManager &parWindowManager); + + virtual void open(); + + void startRepairItem (const MWWorld::Ptr& item); + +protected: + MyGUI::Widget* mRepairBox; + MyGUI::ScrollView* mRepairView; + + MyGUI::Widget* mToolBox; + + MyGUI::ImageBox* mToolIcon; + + MyGUI::TextBox* mUsesLabel; + MyGUI::TextBox* mQualityLabel; + + MyGUI::Button* mCancelButton; + + MWMechanics::Repair mRepair; + + void updateRepairView(); + + void onRepairItem (MyGUI::Widget* sender); + void onCancel (MyGUI::Widget* sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + +}; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 07ea726206..718bb7106e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -56,6 +56,7 @@ #include "cursor.hpp" #include "spellicons.hpp" #include "merchantrepair.hpp" +#include "repair.hpp" using namespace MWGui; @@ -92,6 +93,7 @@ WindowManager::WindowManager( , mEnchantingDialog(NULL) , mTrainingWindow(NULL) , mMerchantRepair(NULL) + , mRepair(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -183,6 +185,7 @@ WindowManager::WindowManager( mEnchantingDialog = new EnchantingDialog(*this); mTrainingWindow = new TrainingWindow(*this); mMerchantRepair = new MerchantRepair(*this); + mRepair = new Repair(*this); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -249,6 +252,7 @@ WindowManager::~WindowManager() delete mCountDialog; delete mQuickKeysMenu; delete mMerchantRepair; + delete mRepair; delete mCursor; cleanupGarbage(); @@ -308,6 +312,7 @@ void WindowManager::updateVisible() mEnchantingDialog->setVisible(false); mTrainingWindow->setVisible(false); mMerchantRepair->setVisible(false); + mRepair->setVisible(false); mHud->setVisible(mHudEnabled); @@ -436,6 +441,9 @@ void WindowManager::updateVisible() case GM_MerchantRepair: mMerchantRepair->setVisible(true); break; + case GM_Repair: + mRepair->setVisible(true); + break; case GM_InterMessageBox: break; case GM_Journal: @@ -1145,6 +1153,11 @@ void WindowManager::startRepair(MWWorld::Ptr actor) mMerchantRepair->startRepair(actor); } +void WindowManager::startRepairItem(MWWorld::Ptr item) +{ + mRepair->startRepairItem(item); +} + const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 2242a8467b..216ab9a6f8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -75,6 +75,7 @@ namespace MWGui class Cursor; class SpellIcons; class MerchantRepair; + class Repair; class WindowManager : public MWBase::WindowManager { @@ -231,6 +232,7 @@ namespace MWGui virtual void startEnchanting(MWWorld::Ptr actor); virtual void startTraining(MWWorld::Ptr actor); virtual void startRepair(MWWorld::Ptr actor); + virtual void startRepairItem(MWWorld::Ptr item); virtual void changePointer (const std::string& name); @@ -269,6 +271,7 @@ namespace MWGui EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; MerchantRepair* mMerchantRepair; + Repair* mRepair; Translation::Storage& mTranslationDataStorage; Cursor* mCursor; diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp new file mode 100644 index 0000000000..8ed4498859 --- /dev/null +++ b/apps/openmw/mwmechanics/repair.cpp @@ -0,0 +1,110 @@ +#include "repair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/npcstats.hpp" + +namespace MWMechanics +{ + +void Repair::repair(const MWWorld::Ptr &itemToRepair) +{ + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::LiveCellRef *ref = + mTool.get(); + + // reduce number of uses left + int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses; + mTool.getCellRef().mCharge = uses-1; + + // unstack tool if required + if (mTool.getRefData().getCount() > 1 && uses == ref->mBase->mData.mUses) + { + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + MWWorld::ContainerStoreIterator it = store.add(mTool); + it->getRefData().setCount(mTool.getRefData().getCount()-1); + it->getCellRef().mCharge = -1; + + mTool.getRefData().setCount(1); + } + + MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player); + + float fatigueTerm = stats.getFatigueTerm(); + int pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified(); + int pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); + int armorerSkill = npcStats.getSkill(ESM::Skill::Armorer).getModified(); + + float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fRepairAmountMult")->getFloat(); + + float toolQuality = ref->mBase->mData.mQuality; + + float x = (0.1 * pcStrength + 0.1 * pcLuck + armorerSkill) * fatigueTerm; + + int roll = static_cast (std::rand()) / RAND_MAX * 100; + if (roll <= x) + { + int y = fRepairAmountMult * toolQuality * roll; + y = std::max(1, y); + + // repair by 'y' points + itemToRepair.getCellRef().mCharge += y; + itemToRepair.getCellRef().mCharge = std::min(itemToRepair.getCellRef().mCharge, + MWWorld::Class::get(itemToRepair).getItemMaxHealth(itemToRepair)); + + // set the OnPCRepair variable on the item's script + std::string script = MWWorld::Class::get(itemToRepair).getScript(itemToRepair); + if(script != "") + itemToRepair.getRefData().getLocals().setVarByInt(script, "onpcrepair", 1); + + // increase skill + MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Armorer, 0); + + MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); + MWBase::Environment::get().getWindowManager()->messageBox("#{sRepairSuccess}"); + } + else + { + MWBase::Environment::get().getSoundManager()->playSound("Repair Fail",1,1); + MWBase::Environment::get().getWindowManager()->messageBox("#{sRepairFailed}"); + } + + // tool used up? + if (mTool.getCellRef().mCharge == 0) + { + mTool.getRefData().setCount(0); + + std::string message = MWBase::Environment::get().getWorld()->getStore().get() + .find("sNotifyMessage51")->getString(); + + MWBase::Environment::get().getWindowManager()->messageBox((boost::format(message) % MWWorld::Class::get(mTool).getName(mTool)).str()); + + // try to find a new tool of the same ID + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + for (MWWorld::ContainerStoreIterator iter (store.begin()); + iter!=store.end(); ++iter) + { + if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, mTool.getCellRef().mRefID)) + { + mTool = *iter; + break; + } + } + } +} + +} diff --git a/apps/openmw/mwmechanics/repair.hpp b/apps/openmw/mwmechanics/repair.hpp new file mode 100644 index 0000000000..6f9a866af1 --- /dev/null +++ b/apps/openmw/mwmechanics/repair.hpp @@ -0,0 +1,23 @@ +#ifndef OPENMW_MWMECHANICS_REPAIR_H +#define OPENMW_MWMECHANICS_REPAIR_H + +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + + class Repair + { + public: + void setTool (const MWWorld::Ptr& tool) { mTool = tool; } + MWWorld::Ptr getTool() { return mTool; } + + void repair (const MWWorld::Ptr& itemToRepair); + + private: + MWWorld::Ptr mTool; + }; + +} + +#endif diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp new file mode 100644 index 0000000000..bd56421165 --- /dev/null +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -0,0 +1,18 @@ +#include "actionrepair.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +namespace MWWorld +{ + ActionRepair::ActionRepair(const Ptr &item) + : Action(false, item) + { + } + + void ActionRepair::executeImp (const Ptr& actor) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair); + MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); + } +} diff --git a/apps/openmw/mwworld/actionrepair.hpp b/apps/openmw/mwworld/actionrepair.hpp new file mode 100644 index 0000000000..1d3ef2bc11 --- /dev/null +++ b/apps/openmw/mwworld/actionrepair.hpp @@ -0,0 +1,17 @@ +#ifndef GAME_MWWORLD_ACTIONREPAIR_H +#define GAME_MWWORLD_ACTIONREPAIR_H + +#include "action.hpp" + +namespace MWWorld +{ + class ActionRepair : public Action + { + virtual void executeImp (const Ptr& actor); + + public: + ActionRepair(const MWWorld::Ptr& item); + }; +} + +#endif diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 223514e086..ac27beb44a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -38,12 +38,6 @@ namespace return sum; } - - bool compare_string_ci(std::string str1, std::string str2) - { - Misc::StringUtils::toLower(str1); - return str1 == str2; - } } MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {} @@ -68,7 +62,11 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) && MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier) && ptr1.mCellRef->mOwner == ptr2.mCellRef->mOwner && ptr1.mCellRef->mSoul == ptr2.mCellRef->mSoul - && ptr1.mCellRef->mCharge == -1) // item that is already partly used up never stacks + // item that is already partly used up never stacks + && (!MWWorld::Class::get(ptr1).hasItemHealth(ptr1) || ptr1.mCellRef->mCharge == -1 + || MWWorld::Class::get(ptr1).getItemMaxHealth(ptr1) == ptr1.mCellRef->mCharge) + && (!MWWorld::Class::get(ptr2).hasItemHealth(ptr2) || ptr2.mCellRef->mCharge == -1 + || MWWorld::Class::get(ptr2).getItemMaxHealth(ptr2) == ptr2.mCellRef->mCharge)) return true; return false; @@ -118,11 +116,11 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) MWWorld::LiveCellRef *gold = ptr.get(); - if (compare_string_ci(gold->mRef.mRefID, "gold_001") - || compare_string_ci(gold->mRef.mRefID, "gold_005") - || compare_string_ci(gold->mRef.mRefID, "gold_010") - || compare_string_ci(gold->mRef.mRefID, "gold_025") - || compare_string_ci(gold->mRef.mRefID, "gold_100")) + if (Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_001") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_005") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_010") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_025") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_100")) { MWWorld::ManualRef ref(esmStore, "Gold_001"); @@ -130,7 +128,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (compare_string_ci((*iter).get()->mRef.mRefID, "gold_001")) + if (Misc::StringUtils::ciEqual((*iter).get()->mRef.mRefID, "gold_001")) { (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); flagAsModified(); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 4adebf1dfd..7da28f0bfa 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -79,6 +79,7 @@ set(MYGUI_FILES openmw_travel_window.layout openmw_persuasion_dialog.layout openmw_merchantrepair.layout + openmw_repair.layout smallbars.png DejaVuLGCSansMono.ttf markers.png diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout new file mode 100644 index 0000000000..2881a5853a --- /dev/null +++ b/files/mygui/openmw_repair.layout @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 13b22ff93d..71e86091c8 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -154,8 +154,8 @@ - - + + From 7beda509fe711190fb952ad33c784c1d1557eba3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Mar 2013 09:53:38 +0100 Subject: [PATCH 0778/1483] Lighting should be done in view space instead of object space, so that attenuation also works correctly for scaled objects --- files/materials/objects.shader | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 46e3abeb3c..ae589a05be 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -54,10 +54,11 @@ #if VERTEX_LIGHTING shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) - shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_object_space_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) + shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) #if VERTEXCOLOR_MODE != 2 shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) #endif @@ -131,11 +132,14 @@ #if VERTEX_LIGHTING + float3 viewPos = shMatrixMult(worldView, shInputPosition).xyz; + float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); + float3 lightDir; float d; lightResult = float4(0,0,0,1); @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (shInputPosition.xyz * lightPosition[@shIterator].w); + lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); d = length(lightDir); lightDir = normalize(lightDir); @@ -143,11 +147,11 @@ #if VERTEXCOLOR_MODE == 2 lightResult.xyz += colour.xyz * lightDiffuse[@shIterator].xyz * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(normalize(normal.xyz), normalize(lightDir)), 0); + * max(dot(viewNormal.xyz, lightDir), 0); #else lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(normalize(normal.xyz), normalize(lightDir)), 0); + * max(dot(viewNormal.xyz, lightDir), 0); #endif #if @shIterator == 0 From 92f00989110bf3371f9be5ffe6b79f8903858c02 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Mar 2013 13:13:34 +0100 Subject: [PATCH 0779/1483] added new constructors for EnumDelegateFactory --- apps/opencs/view/world/enumdelegate.cpp | 11 +++++++++++ apps/opencs/view/world/enumdelegate.hpp | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 7a8b45373d..0dd0a1d594 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -1,6 +1,7 @@ #include "enumdelegate.hpp" +#include #include #include @@ -89,6 +90,16 @@ void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewIte } +CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {} + +CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names) +{ + assert (names); + + for (int i=0; names[i]; ++i) + add (i, names[i]); +} + CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, QObject *parent) const { diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index f11252371e..752ed5be72 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -45,6 +45,11 @@ namespace CSVWorld public: + EnumDelegateFactory(); + + EnumDelegateFactory (const char **names); + ///< \param names Array of char pointer with a 0-pointer as end mark + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. From 0ce962e815bb0f08e2ddfbf576efa216da2b1aa7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Mar 2013 13:13:53 +0100 Subject: [PATCH 0780/1483] added specialisation column to skill table --- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/view/doc/viewmanager.cpp | 8 ++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c44abda2b2..a098fcb7e5 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -31,7 +31,8 @@ namespace CSMWorld Display_Float, Display_Var, Display_GmstVarType, - Display_GlobalVarType + Display_GlobalVarType, + Display_Specialisation }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index a84c9ddf64..43aad889d9 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -202,6 +202,31 @@ namespace CSMWorld return true; } }; + + template + struct SpecialisationColumn : public Column + { + SpecialisationColumn() : Column ("Specialisation", ColumnBase::Display_Specialisation) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mSpecialization; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mSpecialization = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 51ea3e71be..de85beed45 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -38,6 +38,7 @@ CSMWorld::Data::Data() mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new SpecialisationColumn); mSkills.addColumn (new DescriptionColumn); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 33300f67a7..f59be3d997 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -38,6 +38,11 @@ void CSVDoc::ViewManager::updateIndices() CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false) { + static const char *sSpecialisations[] = + { + "Combat", "Magic", "Stealth", 0 + }; + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -45,6 +50,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation, + new CSVWorld::EnumDelegateFactory (sSpecialisations)); } CSVDoc::ViewManager::~ViewManager() From 962b5041296cdf3a0422b9f0c0f29e49a5f2bd5f Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Sat, 23 Mar 2013 16:20:10 +0100 Subject: [PATCH 0781/1483] add dpkg information for mwiniimporter, this blocked debian/ubuntu buildd from building --- apps/mwiniimporter/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index deab88ce28..702f665138 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -22,3 +22,8 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(mwiniimport gcov) endif() + +if(DPKG_PROGRAM) + INSTALL(TARGETS mwiniimport RUNTIME DESTINATION games COMPONENT mwiniimport) +endif() + From 4208d52b1ac67ae40f43d190c8a7aadeff3c3f06 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Mar 2013 14:51:48 +0100 Subject: [PATCH 0782/1483] added use value columns to skills --- apps/opencs/model/world/columns.hpp | 32 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 43aad889d9..1836dbe7f4 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_COLUMNS_H #define CSM_WOLRD_COLUMNS_H +#include + #include "columnbase.hpp" namespace CSMWorld @@ -227,6 +229,36 @@ namespace CSMWorld return true; } }; + + template + struct UseValueColumn : public Column + { + int mIndex; + + UseValueColumn (int index) + : Column ("Use value #" + boost::lexical_cast (index), + ColumnBase::Display_Float), mIndex (index) + {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mUseValue[mIndex]; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mUseValue[mIndex] = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index de85beed45..1b65fecc03 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -39,7 +39,8 @@ CSMWorld::Data::Data() mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); mSkills.addColumn (new SpecialisationColumn); - + for (int i=0; i<4; ++i) + mSkills.addColumn (new UseValueColumn (i)); mSkills.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); From 114f99ddbf0b0e6fb99c116e0622ab9da7dbd47d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Mar 2013 15:10:03 +0100 Subject: [PATCH 0783/1483] add skill records when creating a new base file --- apps/opencs/model/doc/document.cpp | 10 ++++++++++ apps/opencs/model/world/data.cpp | 10 ++++++++++ apps/opencs/model/world/data.hpp | 4 ++++ components/esm/loadskil.cpp | 32 ++++++++++++++++++------------ components/esm/loadskil.hpp | 2 ++ 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 47cf1f6642..deafe8eb84 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -198,6 +198,16 @@ void CSMDoc::Document::createBase() } /// \todo add GMSTs + + for (int i=0; i<27; ++i) + { + ESM::Skill record; + record.mIndex = i; + record.mId = ESM::Skill::getIndexToId (record.mIndex); + record.blank(); + + getData().getSkills().add (record); + } } CSMDoc::Document::Document (const std::vector& files, bool new_) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 1b65fecc03..bc78cb46be 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -74,6 +74,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getGmsts() return mGmsts; } +const CSMWorld::IdCollection& CSMWorld::Data::getSkills() const +{ + return mSkills; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSkills() +{ + return mSkills; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index dc9aee0618..ac953dbece 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -46,6 +46,10 @@ namespace CSMWorld IdCollection& getGmsts(); + const IdCollection& getSkills() const; + + IdCollection& getSkills(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index ac9fc27897..b9d588eef4 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -103,19 +103,7 @@ void Skill::load(ESMReader &esm) // create an ID from the index and the name (only used in the editor and likely to change in the // future) - std::ostringstream stream; - - stream << "#"; - - if (mIndex<10) - stream << "0"; - - stream << mIndex; - - if (mIndex>=0 && mIndex=0 && index Date: Sun, 24 Mar 2013 15:50:29 +0100 Subject: [PATCH 0784/1483] added attribute column to skills --- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 26 ++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/view/doc/viewmanager.cpp | 9 +++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index a098fcb7e5..b5863f8e4e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -32,7 +32,8 @@ namespace CSMWorld Display_Var, Display_GmstVarType, Display_GlobalVarType, - Display_Specialisation + Display_Specialisation, + Display_Attribute }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1836dbe7f4..7764f58709 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -259,6 +259,32 @@ namespace CSMWorld return true; } }; + + template + struct AttributeColumn : public Column + { + AttributeColumn() : Column ("Attribute", ColumnBase::Display_Attribute) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mAttribute; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mAttribute = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index bc78cb46be..4b10a66836 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -38,6 +38,7 @@ CSMWorld::Data::Data() mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new AttributeColumn); mSkills.addColumn (new SpecialisationColumn); for (int i=0; i<4; ++i) mSkills.addColumn (new UseValueColumn (i)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index f59be3d997..bc87728945 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -43,6 +43,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) "Combat", "Magic", "Stealth", 0 }; + static const char *sAttributes[] = + { + "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality", + "Luck", 0 + }; + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -53,6 +59,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation, new CSVWorld::EnumDelegateFactory (sSpecialisations)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, + new CSVWorld::EnumDelegateFactory (sAttributes)); } CSVDoc::ViewManager::~ViewManager() From 7450554ef105bacd7e8ccc2e62d713b895b33a67 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:04:41 +0100 Subject: [PATCH 0785/1483] fixed a broken UniversalId constructor --- apps/opencs/model/world/universalid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6fce376bea..57c276a6d3 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -45,7 +45,7 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId) { std::string::size_type index = universalId.find (':'); - if (index==std::string::npos) + if (index!=std::string::npos) { std::string type = universalId.substr (0, index); From 739e7e7298e10c401ff18aba0637fb4879150164 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:06:40 +0100 Subject: [PATCH 0786/1483] improved record access from ID collection --- apps/opencs/model/world/idcollection.hpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 9b69dfb889..3bf53349e6 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -74,6 +74,8 @@ namespace CSMWorld virtual const RecordBase& getRecord (const std::string& id) const = 0; + virtual const RecordBase& getRecord (int index) const = 0; + virtual void load (ESM::ESMReader& reader, bool base) = 0; }; @@ -139,7 +141,9 @@ namespace CSMWorld /// /// \attention Throw san exception, if the type of \a record does not match. - virtual const RecordBase& getRecord (const std::string& id) const; + virtual const Record& getRecord (const std::string& id) const; + + virtual const Record& getRecord (int index) const; virtual void load (ESM::ESMReader& reader, bool base); @@ -373,11 +377,18 @@ namespace CSMWorld } template - const RecordBase& IdCollection::getRecord (const std::string& id) const + const Record& IdCollection::getRecord (const std::string& id) const { int index = getIndex (id); return mRecords.at (index); } + + template + const Record& IdCollection::getRecord (int index) const + { + return mRecords.at (index); + } + } #endif From dc67ddf39b43c41e3109b71a03122906214d1d68 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:07:04 +0100 Subject: [PATCH 0787/1483] added verifier stage for skill records --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/skillcheck.cpp | 37 ++++++++++++++++++++++++++ apps/opencs/model/tools/skillcheck.hpp | 29 ++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/skillcheck.cpp create mode 100644 apps/opencs/model/tools/skillcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 488e3c65f5..a305d90d93 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid + stage verifier mandatoryid skillcheck ) diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp new file mode 100644 index 0000000000..897aeab473 --- /dev/null +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -0,0 +1,37 @@ + +#include "skillcheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SkillCheckStage::SkillCheckStage (const CSMWorld::IdCollection& skills) +: mSkills (skills) +{} + +int CSMTools::SkillCheckStage::setup() +{ + return mSkills.getSize(); +} + +void CSMTools::SkillCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Skill& skill = mSkills.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Skill, skill.mId); + + for (int i=0; i<4; ++i) + if (skill.mData.mUseValue[i]<0) + { + std::ostringstream stream; + + stream << id.toString() << "|Use value #" << i << " of " << skill.mId << " is negative"; + + messages.push_back (stream.str()); + } + + if (skill.mDescription.empty()) + messages.push_back (id.toString() + "|" + skill.mId + " has an empty description"); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/skillcheck.hpp b/apps/opencs/model/tools/skillcheck.hpp new file mode 100644 index 0000000000..30a3f01cad --- /dev/null +++ b/apps/opencs/model/tools/skillcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SKILLCHECK_H +#define CSM_TOOLS_SKILLCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that skill records are internally consistent + class SkillCheckStage : public Stage + { + const CSMWorld::IdCollection& mSkills; + + public: + + SkillCheckStage (const CSMWorld::IdCollection& skills); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 8dd1c0fe6f..33cc3cc61b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -12,6 +12,7 @@ #include "reportmodel.hpp" #include "mandatoryid.hpp" +#include "skillcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -51,6 +52,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); + + mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); } return mVerifier; From 6c76e97bbc65e8ae101dc6fe7bf427e30a5974fe Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:53:02 +0100 Subject: [PATCH 0788/1483] fixed day count in rest dialogue --- apps/openmw/mwgui/waitdialog.cpp | 20 ++++++++++---------- apps/openmw/mwworld/globals.cpp | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 6e914a669b..df8a52456c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -132,7 +132,7 @@ namespace MWGui case 11: month = "#{sMonthEveningstar}"; break; - default: + default: break; } int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); @@ -142,7 +142,7 @@ namespace MWGui std::string dateTimeText = boost::lexical_cast(MWBase::Environment::get().getWorld ()->getDay ()) + " " - + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay ()+1) + + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay()) + ") " + boost::lexical_cast(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mDateTimeText->setCaptionWithReplacing (dateTimeText); @@ -156,13 +156,13 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats stats = MWWorld::Class::get(player).getCreatureStats(player); const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - + float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; - + bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0); float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); - + // this massive duplication is why it has to be put into helper functions instead float fFatigueReturnBase = store.get().find("fFatigueReturnBase")->getFloat(); float fFatigueReturnMult = store.get().find("fFatigueReturnMult")->getFloat(); @@ -174,7 +174,7 @@ namespace MWGui normalizedEncumbrance = 1; float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified(); - + float healthHours = hourlyHealthDelta >= 0.0 ? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta : 1.0f; @@ -185,9 +185,9 @@ namespace MWGui float fatigueHours = hourlyFatigueDelta >= 0.0 ? (stats.getFatigue().getBase() - stats.getFatigue().getCurrent()) / hourlyFatigueDelta : 1.0f; - + int autoHours = int(std::ceil( std::max(std::max(healthHours, magickaHours), std::max(fatigueHours, 1.0f)) )); // this should use a variadic max if possible - + startWaiting(autoHours); } @@ -201,11 +201,11 @@ namespace MWGui MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2); setVisible(false); mProgressBar.setVisible (true); - + mWaiting = true; mCurHour = 0; mHours = hoursToWait; - + mRemainingTime = 0.05; mProgressBar.setProgress (0, mHours); } diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 9e57910ee0..72bebc0498 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -79,7 +79,7 @@ namespace MWWorld { // vanilla Morrowind does not define dayspassed. Data value; - value.mLong = 0; + value.mLong = 1; // but the addons start counting at 1 :( mVariables.insert (std::make_pair ("dayspassed", std::make_pair ('l', value))); } From f39f6946389525699faefdb8e5aedba30040bee5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:59:25 +0100 Subject: [PATCH 0789/1483] various global variable fixes in editor --- apps/opencs/model/doc/document.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index deafe8eb84..d1462d6a3f 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -150,6 +150,10 @@ void CSMDoc::Document::addOptionalGlobals() ESM::Global global; global.mId = sGlobals[i]; global.mValue.setType (ESM::VT_Long); + + if (i==0) + global.mValue.setInteger (1); // dayspassed starts counting at 1 + addOptionalGlobal (global); } } @@ -189,9 +193,9 @@ void CSMDoc::Document::createBase() record.mId = sGlobals[i]; - record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Int); + record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Long); - if (i==0) + if (i==0 || i==1) record.mValue.setInteger (1); getData().getGlobals().add (record); From f2969e7143d9f050bc2745c54de3a65850db5189 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 12:56:52 +0100 Subject: [PATCH 0790/1483] fixed access to records flagged as deleted --- apps/opencs/model/world/record.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index e442d0a391..c8f728e7d1 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -62,7 +62,7 @@ namespace CSMWorld if (mState==State_Erased) throw std::logic_error ("attempt to access a deleted record"); - return mState==State_BaseOnly ? mBase : mModified; + return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified; } template From c7275965b8c8e419eec920db231f59270bdf1059 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 13:22:06 +0100 Subject: [PATCH 0791/1483] added basic class record table --- apps/opencs/model/world/data.cpp | 7 +++++++ apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 7 +++++-- components/esm/loadclas.cpp | 14 ++++++++++++++ components/esm/loadclas.hpp | 4 ++++ 9 files changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 4b10a66836..2b635d9abe 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -44,9 +44,15 @@ CSMWorld::Data::Data() mSkills.addColumn (new UseValueColumn (i)); mSkills.addColumn (new DescriptionColumn); + mClasses.addColumn (new StringIdColumn); + mClasses.addColumn (new RecordStateColumn); + mClasses.addColumn (new SpecialisationColumn); + mClasses.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); + addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); } CSMWorld::Data::~Data() @@ -122,6 +128,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_GLOB: mGlobals.load (reader, base); break; case ESM::REC_GMST: mGmsts.load (reader, base); break; case ESM::REC_SKIL: mSkills.load (reader, base); break; + case ESM::REC_CLAS: mClasses.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index ac953dbece..7baf03259e 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -22,6 +23,7 @@ namespace CSMWorld IdCollection mGlobals; IdCollection mGmsts; IdCollection mSkills; + IdCollection mClasses; std::vector mModels; std::map mModelIndex; diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 57c276a6d3..a85b30c2a8 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -20,6 +20,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -29,6 +30,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index a412cb6b1e..4c4d95654b 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -39,7 +39,9 @@ namespace CSMWorld Type_Gmsts, Type_Gmst, Type_Skills, - Type_Skill + Type_Skill, + Type_Classes, + Type_Class }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 267ddf26cc..2ef66593f7 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -90,6 +90,10 @@ void CSVDoc::View::setupWorldMenu() connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView())); world->addAction (skills); + QAction *classes = new QAction (tr ("Classes"), this); + connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView())); + world->addAction (classes); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -253,6 +257,11 @@ void CSVDoc::View::addSkillsSubView() addSubView (CSMWorld::UniversalId::Type_Skills); } +void CSVDoc::View::addClassesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Classes); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 4c5aa40784..bc8e8fc26d 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -117,6 +117,8 @@ namespace CSVDoc void addGmstsSubView(); void addSkillsSubView(); + + void addClassesSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index bdff0017b4..5d715ea21e 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -17,6 +17,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Skills, new CSVDoc::SubViewFactoryWithCreateFlag (false)); - manager.add (CSMWorld::UniversalId::Type_Global, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Classes, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); + +// manager.add (CSMWorld::UniversalId::Type_Global, +// new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index a626689504..d9f367fd63 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -35,4 +35,18 @@ void Class::save(ESMWriter &esm) esm.writeHNOString("DESC", mDescription); } + void Class::blank() + { + mName.clear(); + mDescription.clear(); + + mData.mAttribute[0] = mData.mAttribute[1] = 0; + mData.mSpecialization = 0; + mData.mIsPlayable = 0; + mData.mCalc = 0; + + for (int i=0; i<5; ++i) + for (int i2=0; i2<2; ++i2) + mData.mSkills[i][i2] = 0; + } } diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 264e342e63..ac596af32c 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -65,6 +65,10 @@ struct Class void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). + }; } #endif From 65cda580db62ccba881a6518d880c5027c38824a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 14:31:46 +0100 Subject: [PATCH 0792/1483] added attributes to class table --- apps/opencs/model/world/columns.hpp | 53 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++ 2 files changed, 56 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7764f58709..b41e98f409 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -285,6 +285,59 @@ namespace CSMWorld } }; + template + struct NameColumn : public Column + { + NameColumn() : Column ("Name", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mName.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mName = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct AttributesColumn : public Column + { + int mIndex; + + AttributesColumn (int index) + : Column ("Attribute #" + boost::lexical_cast (index), + ColumnBase::Display_Attribute), mIndex (index) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mAttribute[mIndex]; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mAttribute[mIndex] = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 2b635d9abe..b0a8b95a6f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -46,6 +46,9 @@ CSMWorld::Data::Data() mClasses.addColumn (new StringIdColumn); mClasses.addColumn (new RecordStateColumn); + mClasses.addColumn (new NameColumn); + mClasses.addColumn (new AttributesColumn (0)); + mClasses.addColumn (new AttributesColumn (1)); mClasses.addColumn (new SpecialisationColumn); mClasses.addColumn (new DescriptionColumn); From 4be0c6b70867f3514c088c522f687d45da855dd6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Mar 2013 17:32:01 +0100 Subject: [PATCH 0793/1483] Fix topics not being selectable for creatures --- apps/openmw/mwgui/dialogue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 9a7e51874f..d045725fb1 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -230,14 +230,14 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) { if (!mEnabled) return; - int separatorPos = mTopicsList->getItemCount(); + int separatorPos = 0; for (unsigned int i=0; igetItemCount(); ++i) { if (mTopicsList->getItemNameAt(i) == "") separatorPos = i; } - if (id > separatorPos) + if (id >= separatorPos) MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); else { From 6a2b87e14a5ed565caf4f7e208c9c398d8a6611a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Mar 2013 17:37:59 +0100 Subject: [PATCH 0794/1483] Fix dialogue response coloring for creatures --- apps/openmw/mwgui/dialogue.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d045725fb1..bfbd60b07d 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -389,10 +389,17 @@ std::string DialogueWindow::parseText(const std::string& text) std::vector topics; + bool hasSeparator = false; + for (unsigned int i=0; igetItemCount(); ++i) + { + if (mTopicsList->getItemNameAt(i) == "") + hasSeparator = true; + } + for(unsigned int i = 0;igetItemCount();i++) { std::string keyWord = mTopicsList->getItemNameAt(i); - if (separatorReached) + if (separatorReached || !hasSeparator) topics.push_back(keyWord); else if (keyWord == "") separatorReached = true; From ea3b14f2d25d3174ad57d7fa7d4d7acc23e7d0ef Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Mar 2013 09:43:13 +0100 Subject: [PATCH 0795/1483] added skill columns to class --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/columns.hpp | 46 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 4 +++ components/esm/loadskil.cpp | 7 +++-- components/esm/loadskil.hpp | 2 +- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index d1462d6a3f..acca877f0a 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -207,7 +207,7 @@ void CSMDoc::Document::createBase() { ESM::Skill record; record.mIndex = i; - record.mId = ESM::Skill::getIndexToId (record.mIndex); + record.mId = ESM::Skill::indexToId (record.mIndex); record.blank(); getData().getSkills().add (record); diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b41e98f409..902d7d86fc 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_COLUMNS_H #define CSM_WOLRD_COLUMNS_H +#include + #include #include "columnbase.hpp" @@ -338,6 +340,50 @@ namespace CSMWorld return true; } }; + + template + struct SkillsColumn : public Column + { + int mIndex; + bool mMajor; + + SkillsColumn (int index, bool major) + : Column ((major ? "Major Skill #" : "Minor Skill #")+ + boost::lexical_cast (index), ColumnBase::Display_String), + mIndex (index), mMajor (major) + {} + + virtual QVariant get (const Record& record) const + { + int skill = record.get().mData.mSkills[mIndex][mMajor ? 1 : 0]; + + return QString::fromUtf8 (ESM::Skill::indexToId (skill).c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + std::istringstream stream (data.toString().toUtf8().constData()); + + int index = -1; + char c; + + stream >> c >> index; + + if (index!=-1) + { + ESXRecordT record2 = record.get(); + + record2.mData.mSkills[mIndex][mMajor ? 1 : 0] = index; + + record.setModified (record2); + } + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b0a8b95a6f..917be26325 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -50,6 +50,10 @@ CSMWorld::Data::Data() mClasses.addColumn (new AttributesColumn (0)); mClasses.addColumn (new AttributesColumn (1)); mClasses.addColumn (new SpecialisationColumn); + for (int i=0; i<5; ++i) + mClasses.addColumn (new SkillsColumn (i, true)); + for (int i=0; i<5; ++i) + mClasses.addColumn (new SkillsColumn (i, false)); mClasses.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b9d588eef4..b7259db94e 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -2,6 +2,8 @@ #include +#include + #include "esmreader.hpp" #include "esmwriter.hpp" @@ -103,8 +105,9 @@ void Skill::load(ESMReader &esm) // create an ID from the index and the name (only used in the editor and likely to change in the // future) - mId = getIndexToId (mIndex); + mId = indexToId (mIndex); } + void Skill::save(ESMWriter &esm) { esm.writeHNT("INDX", mIndex); @@ -120,7 +123,7 @@ void Skill::save(ESMWriter &esm) mDescription.clear(); } - std::string Skill::getIndexToId (int index) + std::string Skill::indexToId (int index) { std::ostringstream stream; diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 83a4d8bfd9..43f4fc45e9 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -79,7 +79,7 @@ struct Skill void blank(); ///< Set record to default state (does not touch the ID/index). - static std::string getIndexToId (int index); + static std::string indexToId (int index); }; } #endif From 82f1cee116a740e853be87a732cfbf52dac3ec1c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Mar 2013 09:51:39 +0100 Subject: [PATCH 0796/1483] added is-playable column to class --- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index b5863f8e4e..5c2ce8a676 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -33,7 +33,8 @@ namespace CSMWorld Display_GmstVarType, Display_GlobalVarType, Display_Specialisation, - Display_Attribute + Display_Attribute, + Display_Boolean }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 902d7d86fc..cbcddd972d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -384,6 +384,31 @@ namespace CSMWorld return true; } }; + + template + struct PlayableColumn : public Column + { + PlayableColumn() : Column ("Playable", ColumnBase::Display_Boolean) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mIsPlayable!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mIsPlayable = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 917be26325..7b3e667715 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -54,6 +54,7 @@ CSMWorld::Data::Data() mClasses.addColumn (new SkillsColumn (i, true)); for (int i=0; i<5; ++i) mClasses.addColumn (new SkillsColumn (i, false)); + mClasses.addColumn (new PlayableColumn); mClasses.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); From efe6a3ebeec495a213a75ed3c072d9d2eb1c8c95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Mar 2013 18:01:01 +0100 Subject: [PATCH 0797/1483] Fix compile error & warnings --- apps/openmw/mwmechanics/aitravel.cpp | 6 +-- apps/openmw/mwmechanics/aitravel.hpp | 60 ++++++++++++++-------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 94f6fd8928..2c5260a625 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -46,7 +46,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; - for(int i=1; imPoints.size();i++) + for(unsigned int i=1; imPoints.size();++i) { if(distance(grid->mPoints[i],x,y,z)mPoints.size();i++) + for(unsigned int i = 0;imPoints.size();++i) { PointID pID = boost::add_vertex(graph); graph[pID].mX = pathgrid->mPoints[i].mX + xCell; @@ -147,7 +147,7 @@ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCe graph[pID].mZ = pathgrid->mPoints[i].mZ; } - for(int i = 0;imEdges.size();i++) + for(unsigned int i = 0;imEdges.size();++i) { PointID u = pathgrid->mEdges[i].mV0; PointID v = pathgrid->mEdges[i].mV1; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 3d220cb7e3..ef2359ba91 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,35 +1,35 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H - -#include "aipackage.hpp" -#include "components\esm\loadpgrd.hpp" -#include - -namespace MWMechanics -{ - class AiTravel : public AiPackage - { - public: - AiTravel(float x, float y, float z); - virtual AiTravel *clone() const; - - virtual bool execute (const MWWorld::Ptr& actor); - ///< \return Package completed? - - virtual int getTypeId() const; - - private: - float mX; - float mY; - float mZ; - - int cellX; - int cellY; - - bool isPathConstructed; - std::list mPath; - - }; + +#include "aipackage.hpp" +#include +#include + +namespace MWMechanics +{ + class AiTravel : public AiPackage + { + public: + AiTravel(float x, float y, float z); + virtual AiTravel *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + float mX; + float mY; + float mZ; + + int cellX; + int cellY; + + bool isPathConstructed; + std::list mPath; + + }; } #endif From 6f1575d42a046bff854f0a79cb834e6aaf38f4fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Mar 2013 17:27:43 +0100 Subject: [PATCH 0798/1483] CELL record corrections --- apps/esmtool/esmtool.cpp | 5 ++++- apps/openmw/mwclass/misc.cpp | 13 +++++++++---- apps/openmw/mwworld/containerstore.cpp | 3 ++- apps/openmw/mwworld/manualref.hpp | 5 +++-- components/esm/loadcell.cpp | 24 ++++++++++++++++-------- components/esm/loadcell.hpp | 12 +++++++++--- 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 521383f3ff..d682cf88b9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -227,7 +227,10 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Refnum: " << ref.mRefnum << std::endl; std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n"; - std::cout << " Uses/health: " << ref.mCharge << " NAM9: " << ref.mNam9 << std::endl; + std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; + std::cout << " Uses/health: '" << ref.mCharge << "'\n"; + std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; + std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; } } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 07e41bcfa6..31ae1cfb05 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -89,7 +89,9 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mValue; + int value = (ptr.getCellRef().mGoldValue == 1) ? ref->mBase->mData.mValue : ptr.getCellRef().mGoldValue; + + return value; } void Miscellaneous::registerSelf() @@ -151,8 +153,10 @@ namespace MWClass int count = ptr.getRefData().getCount(); bool isGold = (ref->mBase->mName == store.get().find("sGold")->getString()); - if (isGold && count == 1) - count = ref->mBase->mData.mValue; + if (isGold && ptr.getCellRef().mGoldValue != 1) + count = ptr.getCellRef().mGoldValue; + else if (isGold) + count *= ref->mBase->mData.mValue; std::string countString; if (!isGold) @@ -214,7 +218,8 @@ namespace MWClass MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell); - newPtr.getRefData ().setCount(goldAmount); + newPtr.getRefData ().setCount(1); + newPtr.getCellRef().mGoldValue = goldAmount; } else { MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ac27beb44a..e5b68841b8 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -124,7 +124,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) { MWWorld::ManualRef ref(esmStore, "Gold_001"); - int count = (ptr.getRefData().getCount() == 1) ? gold->mBase->mData.mValue : ptr.getRefData().getCount(); + int count = MWWorld::Class::get(ptr).getValue(ptr) * ptr.getRefData().getCount(); + ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 58395d8798..6616165fae 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -69,10 +69,11 @@ namespace MWWorld cellRef.mScale = 1; cellRef.mFactIndex = 0; cellRef.mCharge = -1; - cellRef.mNam9 = 0; + cellRef.mGoldValue = 1; + cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; cellRef.mLockLevel = 0; - cellRef.mUnam = 0; + cellRef.mReferenceBlocked = 0; } const Ptr& getPtr() const diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 0731a8ff80..5cbf1de2b7 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -43,11 +43,14 @@ void CellRef::save(ESMWriter &esm) esm.writeHNT("INDX", mFactIndex); } + if (mEnchantmentCharge != -1) + esm.writeHNT("XCHG", mEnchantmentCharge); + if (mCharge != -1) esm.writeHNT("INTV", mCharge); - if (mNam9 != 0) { - esm.writeHNT("NAM9", mNam9); + if (mGoldValue != 1) { + esm.writeHNT("NAM9", mGoldValue); } if (mTeleport) @@ -62,8 +65,8 @@ void CellRef::save(ESMWriter &esm) esm.writeHNOCString("KNAM", mKey); esm.writeHNOCString("TNAM", mTrap); - if (mUnam != -1) { - esm.writeHNT("UNAM", mUnam); + if (mReferenceBlocked != -1) { + esm.writeHNT("UNAM", mReferenceBlocked); } if (mFltv != 0) { esm.writeHNT("FLTV", mFltv); @@ -281,10 +284,15 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mFactIndex = -2; esm.getHNOT(ref.mFactIndex, "INDX"); - ref.mNam9 = 0; + ref.mGoldValue = 1; ref.mCharge = -1; + ref.mEnchantmentCharge = -1; + + esm.getHNOT(ref.mEnchantmentCharge, "XCHG"); + esm.getHNOT(ref.mCharge, "INTV"); - esm.getHNOT(ref.mNam9, "NAM9"); + + esm.getHNOT(ref.mGoldValue, "NAM9"); // Present for doors that teleport you to another cell. if (esm.isNextSub("DODT")) @@ -302,9 +310,9 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mKey = esm.getHNOString("KNAM"); ref.mTrap = esm.getHNOString("TNAM"); - ref.mUnam = -1; + ref.mReferenceBlocked = -1; ref.mFltv = 0; - esm.getHNOT(ref.mUnam, "UNAM"); + esm.getHNOT(ref.mReferenceBlocked, "UNAM"); esm.getHNOT(ref.mFltv, "FLTV"); esm.getHNOT(ref.mPos, "DATA", 24); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 97aa86ba0f..afc953f54c 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -56,7 +56,11 @@ public: // For tools (lockpicks, probes, repair hammer) it is the remaining uses. int mCharge; - int mNam9; + // Remaining enchantment charge + float mEnchantmentCharge; + + // This is 5 for Gold_005 references, 100 for Gold_100 and so on. + int mGoldValue; // For doors - true if this door teleports to somewhere else, false // if it should open through animation. @@ -72,8 +76,10 @@ public: int mLockLevel; std::string mKey, mTrap; // Key and trap ID names, if any - // No idea - occurs ONCE in Morrowind.esm, for an activator - signed char mUnam; + // This corresponds to the "Reference Blocked" checkbox in the construction set, + // which prevents editing that reference. + // -1 is not blocked, otherwise it is blocked. + signed char mReferenceBlocked; // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. int mDeleted; From 406488d086f78006256b00416f829fefd5b9b170 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Mar 2013 17:39:49 +0100 Subject: [PATCH 0799/1483] Soulgem value should be multiplied by the trapped soul --- apps/openmw/mwclass/misc.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 31ae1cfb05..b971fa6f34 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -91,6 +91,12 @@ namespace MWClass int value = (ptr.getCellRef().mGoldValue == 1) ? ref->mBase->mData.mValue : ptr.getCellRef().mGoldValue; + if (ptr.getCellRef().mSoul != "") + { + const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mRef.mSoul); + value *= creature->mData.mSoul; + } + return value; } @@ -178,7 +184,7 @@ namespace MWClass if (!isGold) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); + text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); } if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { From 564256c4e13f9ea2348de901fc73e0f0fe1d2eae Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Mar 2013 18:04:15 +0100 Subject: [PATCH 0800/1483] Fix the spell icon panel being visible when it shouldn't. --- apps/openmw/mwgui/spellicons.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 16e02ebba1..206db51ed0 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -139,12 +139,13 @@ namespace MWGui } } - parent->setVisible(effects.size() != 0); - int w=2; + if (adjustSize) { int s = effects.size() * 16+4; + if (!effects.size()) + s = 0; int diff = parent->getWidth() - s; parent->setSize(s, parent->getHeight()); parent->setPosition(parent->getLeft()+diff, parent->getTop()); From 6643fe789cb3a909af82f245b8b743c4853bf11d Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 28 Mar 2013 17:41:00 +0100 Subject: [PATCH 0801/1483] Enchanting system --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 39 +++-- apps/openmw/mwclass/armor.cpp | 15 ++ apps/openmw/mwclass/armor.hpp | 2 + apps/openmw/mwclass/book.cpp | 24 ++++ apps/openmw/mwclass/book.hpp | 4 + apps/openmw/mwclass/clothing.cpp | 15 ++ apps/openmw/mwclass/clothing.hpp | 2 + apps/openmw/mwclass/weapon.cpp | 15 ++ apps/openmw/mwclass/weapon.hpp | 2 + apps/openmw/mwgui/enchantingdialog.cpp | 104 ++++++++++++-- apps/openmw/mwgui/enchantingdialog.hpp | 13 +- apps/openmw/mwgui/spellcreationdialog.cpp | 10 +- apps/openmw/mwgui/spellcreationdialog.hpp | 5 +- apps/openmw/mwmechanics/enchanting.cpp | 164 ++++++++++++++++++++++ apps/openmw/mwmechanics/enchanting.hpp | 41 ++++++ apps/openmw/mwworld/class.cpp | 5 + apps/openmw/mwworld/class.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 25 ++++ apps/openmw/mwworld/worldimp.hpp | 29 +++- 20 files changed, 482 insertions(+), 36 deletions(-) create mode 100644 apps/openmw/mwmechanics/enchanting.cpp create mode 100644 apps/openmw/mwmechanics/enchanting.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0edc18afba..7b79a8fdf5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate + aiescort aiactivate enchanting ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 642291eefb..041e2cc1c1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -243,27 +243,44 @@ namespace MWBase ///< Toggle a render mode. ///< \return Resulting mode - virtual const ESM::Potion *createRecord (const ESM::Potion& record) - = 0; - ///< Create a new recrod (of type potion) in the ESM store. + virtual const ESM::Potion *createRecord (const ESM::Potion& record) = 0; + ///< Create a new record (of type potion) in the ESM store. /// \return pointer to created record - virtual const ESM::Spell *createRecord (const ESM::Spell& record) - = 0; - ///< Create a new recrod (of type spell) in the ESM store. + virtual const ESM::Spell *createRecord (const ESM::Spell& record) = 0; + ///< Create a new record (of type spell) in the ESM store. /// \return pointer to created record - virtual const ESM::Class *createRecord (const ESM::Class& record) - = 0; - ///< Create a new recrod (of type class) in the ESM store. + virtual const ESM::Class *createRecord (const ESM::Class& record) = 0; + ///< Create a new record (of type class) in the ESM store. /// \return pointer to created record virtual const ESM::Cell *createRecord (const ESM::Cell& record) = 0; - ///< Create a new recrod (of type cell) in the ESM store. + ///< Create a new record (of type cell) in the ESM store. /// \return pointer to created record virtual const ESM::NPC *createRecord(const ESM::NPC &record) = 0; - ///< Create a new recrod (of type npc) in the ESM store. + ///< Create a new record (of type npc) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Armor *createRecord (const ESM::Armor& record) = 0; + ///< Create a new record (of type armor) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Weapon *createRecord (const ESM::Weapon& record) = 0; + ///< Create a new record (of type weapon) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Clothing *createRecord (const ESM::Clothing& record) = 0; + ///< Create a new record (of type clothing) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record) = 0; + ///< Create a new record (of type enchantment) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Book *createRecord (const ESM::Book& record) = 0; + ///< Create a new record (of type book) in the ESM store. /// \return pointer to created record virtual void update (float duration, bool paused) = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 130c0515d0..02ed743dff 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,6 +16,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/manualref.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -273,6 +274,20 @@ namespace MWClass return ref->mBase->mEnchant; } + MWWorld::Ptr Armor::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + ESM::Armor oldItem = *store.get().find(ptr.getCellRef().mRefID); + ESM::Armor newItem = oldItem; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return ref.getPtr(); + } + boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index ff45411ed2..2c79321bb2 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,6 +65,8 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 4e29fa6845..9714bc06e7 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -11,6 +11,7 @@ #include "../mwworld/actionread.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/manualref.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -147,6 +148,21 @@ namespace MWClass return ref->mBase->mEnchant; } + MWWorld::Ptr Book::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + ESM::Book oldItem = *store.get().find(ptr.getCellRef().mRefID); + ESM::Book newItem = oldItem; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mIsScroll = 1; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return ref.getPtr(); + } + boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const { return boost::shared_ptr(new MWWorld::ActionRead(ptr)); @@ -160,4 +176,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mBooks.insert(*ref), &cell); } + + short Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mEnchant; + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index acb1aac06e..950f2be413 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,10 +51,14 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index f5f71a7767..813746fea2 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/manualref.hpp" #include "../mwgui/tooltips.hpp" @@ -221,6 +222,20 @@ namespace MWClass return ref->mBase->mEnchant; } + MWWorld::Ptr Clothing::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + ESM::Clothing oldItem = *store.get().find(ptr.getCellRef().mRefID); + ESM::Clothing newItem = oldItem; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return ref.getPtr(); + } + boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index f01c78afce..e705c113bf 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,6 +59,8 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0f6e86811e..79ed66a501 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/manualref.hpp" #include "../mwgui/tooltips.hpp" @@ -361,6 +362,20 @@ namespace MWClass return ref->mBase->mEnchant; } + MWWorld::Ptr Weapon::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + ESM::Weapon oldItem = *store.get().find(ptr.getCellRef().mRefID); + ESM::Weapon newItem = oldItem; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return ref.getPtr(); + } + boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index bf34172516..24da3fe64a 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,6 +65,8 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 673739cbf3..5c31a32669 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -5,9 +5,11 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/manualref.hpp" #include "itemselection.hpp" #include "container.hpp" +#include "inventorywindow.hpp" namespace MWGui { @@ -17,8 +19,9 @@ namespace MWGui : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) , EffectEditorBase(parWindowManager) , mItemSelectionDialog(NULL) - , mCurrentEnchantmentPoints(0) + , mEnchanting(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) { + getWidget(mName, "NameEdit"); getWidget(mCancelButton, "CancelButton"); getWidget(mAvailableEffectsList, "AvailableEffects"); getWidget(mUsedEffectsView, "UsedEffects"); @@ -36,6 +39,8 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onCancelButtonClicked); mItemBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectItem); mSoulBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectSoul); + mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onBuyButtonClicked); + mTypeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onTypeButtonClicked); } EnchantingDialog::~EnchantingDialog() @@ -52,9 +57,32 @@ namespace MWGui void EnchantingDialog::updateLabels() { - mEnchantmentPoints->setCaption(boost::lexical_cast(mCurrentEnchantmentPoints) - + " / " + (mItem.isEmpty() ? "0" : boost::lexical_cast( - MWWorld::Class::get(mItem).getEnchantmentPoints(mItem)))); + mEnchantmentPoints->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost()) + + " / " + boost::lexical_cast(mEnchanting.getMaxEnchantValue())); + + mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); + + mCastCost->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost())); + + switch(mEnchanting.getEnchantType()) + { + case 0: + mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastOnce","Cast Once")); + mAddEffectDialog.constantEffect=false; + break; + case 1: + mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenStrikes", "When Strikes")); + mAddEffectDialog.constantEffect=false; + break; + case 2: + mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenUsed", "When Used")); + mAddEffectDialog.constantEffect=false; + break; + case 3: + mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastConstant", "Cast Constant")); + mAddEffectDialog.constantEffect=true; + break; + } } void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) @@ -105,7 +133,8 @@ namespace MWGui image->setUserData(item); image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem); - mItem = item; + mEnchanting.setOldItem(item); + mEnchanting.nextEnchantType(); updateLabels(); } @@ -113,7 +142,7 @@ namespace MWGui { while (mItemBox->getChildCount ()) MyGUI::Gui::getInstance ().destroyWidget (mItemBox->getChildAt(0)); - mItem = MWWorld::Ptr(); + mEnchanting.setOldItem(MWWorld::Ptr()); updateLabels(); } @@ -125,6 +154,13 @@ namespace MWGui void EnchantingDialog::onSoulSelected(MWWorld::Ptr item) { mItemSelectionDialog->setVisible(false); + mEnchanting.setSoulGem(item); + + if(mEnchanting.getGemCharge()==0) + { + mWindowManager.messageBox ("#{sNotifyMessage32}", std::vector()); + return; + } while (mSoulBox->getChildCount ()) MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); @@ -139,8 +175,6 @@ namespace MWGui image->setUserString ("ToolTipType", "ItemPtr"); image->setUserData(item); image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); - - mSoul = item; updateLabels(); } @@ -148,7 +182,7 @@ namespace MWGui { while (mSoulBox->getChildCount ()) MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); - mSoul = MWWorld::Ptr(); + mEnchanting.setSoulGem(MWWorld::Ptr()); updateLabels(); } @@ -170,4 +204,56 @@ namespace MWGui //mWindowManager.messageBox("#{sInventorySelectNoSoul}"); } + + void EnchantingDialog::notifyEffectsChanged () + { + mEffectList.mList = mEffects; + mEnchanting.setEffect(mEffectList); + updateLabels(); + } + + void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender) + { + mEnchanting.nextEnchantType(); + updateLabels(); + } + + void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) + { + if (mEffects.size() <= 0) + { + mWindowManager.messageBox ("#{sNotifyMessage30}", std::vector()); + return; + } + + if (mName->getCaption ().empty()) + { + mWindowManager.messageBox ("#{sNotifyMessage10}", std::vector()); + return; + } + + if (boost::lexical_cast(mPrice->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) + { + mWindowManager.messageBox ("#{sNotifyMessage18}", std::vector()); + return; + } + + if (mEnchanting.soulEmpty()) + { + mWindowManager.messageBox ("#{sNotifyMessage52}", std::vector()); + return; + } + + if (mEnchanting.itemEmpty()) + { + mWindowManager.messageBox ("#{sNotifyMessage11}", std::vector()); + return; + } + + mEnchanting.setNewItemName(mName->getCaption()); + mEnchanting.setEffect(mEffectList); + + mEnchanting.create(); + mWindowManager.removeGuiMode (GM_Enchanting); + } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index bcebb799df..60445a8dc3 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -7,6 +7,8 @@ #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/enchanting.hpp" + namespace MWGui { @@ -23,6 +25,7 @@ namespace MWGui protected: virtual void onReferenceUnavailable(); + virtual void notifyEffectsChanged (); void onCancelButtonClicked(MyGUI::Widget* sender); void onSelectItem (MyGUI::Widget* sender); @@ -34,8 +37,9 @@ namespace MWGui void onItemCancel(); void onSoulSelected(MWWorld::Ptr item); void onSoulCancel(); - + void onBuyButtonClicked(MyGUI::Widget* sender); void updateLabels(); + void onTypeButtonClicked(MyGUI::Widget* sender); ItemSelectionDialog* mItemSelectionDialog; @@ -46,15 +50,14 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; + MyGUI::TextBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; MyGUI::TextBox* mPrice; - MWWorld::Ptr mItem; - MWWorld::Ptr mSoul; - - float mCurrentEnchantmentPoints; + MWMechanics::Enchanting mEnchanting; + ESM::EffectList mEffectList; }; } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 8395864521..ea91ac278f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -72,6 +72,7 @@ namespace MWGui mMagnitudeMaxSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged); mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged); mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged); + constantEffect=false; } void EditEffectDialog::open() @@ -164,7 +165,7 @@ namespace MWGui mMagnitudeBox->setVisible (true); curY += mMagnitudeBox->getSize().height; } - if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)&&constantEffect==false) { mDurationBox->setPosition(mDurationBox->getPosition().left, curY); mDurationBox->setVisible (true); @@ -454,10 +455,13 @@ namespace MWGui mAvailableEffectsList->clear (); + int i=0; for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString()); + mButtonMapping[i] = *it; + ++i; } mAvailableEffectsList->adjustSize (); @@ -466,7 +470,6 @@ namespace MWGui std::string name = MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString(); MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); - w->setUserData(*it); ToolTips::createMagicEffectToolTip (w, *it); } @@ -518,7 +521,8 @@ namespace MWGui return; } - short effectId = *sender->getUserData(); + int buttonId = *sender->getUserData(); + short effectId = mButtonMapping[buttonId]; for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 4d27ec1c6f..8f1c071804 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -24,7 +24,7 @@ namespace MWGui void newEffect (const ESM::MagicEffect* effect); void editEffect (ESM::ENAMstruct effect); - + bool constantEffect; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Effect; EventHandle_Effect eventEffectAdded; @@ -69,7 +69,6 @@ namespace MWGui void onMagnitudeMaxChanged (MyGUI::ScrollBar* sender, size_t pos); void onDurationChanged (MyGUI::ScrollBar* sender, size_t pos); void onAreaChanged (MyGUI::ScrollBar* sender, size_t pos); - void setMagicEffect(const ESM::MagicEffect* effect); void updateBoxes(); @@ -88,6 +87,8 @@ namespace MWGui protected: + std::map mButtonMapping; // maps button ID to effect ID + Widgets::MWList* mAvailableEffectsList; MyGUI::ScrollView* mUsedEffectsView; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp new file mode 100644 index 0000000000..d3352226b1 --- /dev/null +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -0,0 +1,164 @@ +#include "enchanting.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/containerstore.hpp" +namespace MWMechanics +{ + Enchanting::Enchanting(MWWorld::Ptr enchanter): + mEnchanter(enchanter), + mEnchantType(0) + {} + + void Enchanting::setOldItem(MWWorld::Ptr oldItem) + { + mOldItemPtr=oldItem; + if(!itemEmpty()) + { + mObjectType = mOldItemPtr.getTypeName(); + mOldItemId = mOldItemPtr.getCellRef().mRefID; + } + else + { + mObjectType=""; + mOldItemId=""; + } + } + + void Enchanting::setNewItemName(std::string s) + { + mNewItemName=s; + } + + void Enchanting::setEffect(ESM::EffectList effectList) + { + mEffectList=effectList; + } + + int Enchanting::getEnchantType() + { + return mEnchantType; + } + + void Enchanting::setSoulGem(MWWorld::Ptr soulGem) + { + mSoulGemPtr=soulGem; + } + + void Enchanting::create() + { + mEnchantment.mData.mCharge = getGemCharge(); + if(mEnchantType==3) + { + mEnchantment.mData.mCharge=0; + } + mEnchantment.mData.mType = mEnchantType; + mEnchantment.mData.mCost = getEnchantCost(); + mEnchantment.mEffects = mEffectList; + const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); + + MWWorld::Ptr newobj = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobj.getCellRef().mRefID); + MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); + + mOldItemPtr.getRefData().setCount(0); + mSoulGemPtr.getRefData().setCount(0); + } + + void Enchanting::nextEnchantType() + { + mEnchantType++; + if (itemEmpty()) + { + mEnchantType = 0; + return; + } + if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) + { + switch(mEnchantType) + { + case 1: + mEnchantType = 2; + case 3: + if(getGemCharge()<400) + mEnchantType=2; + case 4: + mEnchantType = 2; + } + } + else if(mObjectType == typeid(ESM::Weapon).name()) + { + switch(mEnchantType) + { + case 3: + mEnchantType = 1; + } + } + else if(mObjectType == typeid(ESM::Book).name()) + { + mEnchantType=0; + } + } + + int Enchanting::getEnchantCost() + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + float cost = 0; + std::vector mEffects = mEffectList.mList; + int i=mEffects.size(); + for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) + { + const ESM::MagicEffect* effect = store.get().find(it->mEffectID); + + float cost1 = ((it->mMagnMin + it->mMagnMax)*it->mDuration*effect->mData.mBaseCost*0.025); + + float cost2 = (std::max(1, it->mArea)*0.125*effect->mData.mBaseCost); + + if(mEnchantType==3) + { + cost1 *= 100; + cost2 *= 2; + } + if(effect->mData.mFlags & ESM::MagicEffect::CastTarget) + cost1 *= 1.5; + + float fullcost = cost1+cost2; + fullcost*= i; + i--; + + cost+=fullcost; + } + return cost; + } + int Enchanting::getGemCharge() + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + if(soulEmpty()) + return 0; + if(mSoulGemPtr.getCellRef().mSoul=="") + return 0; + const ESM::Creature* soul = store.get().find(mSoulGemPtr.getCellRef().mSoul); + return soul->mData.mSoul; + } + + int Enchanting::getMaxEnchantValue() + { + if (itemEmpty()) + return 0; + return MWWorld::Class::get(mOldItemPtr).getEnchantmentPoints(mOldItemPtr); + } + bool Enchanting::soulEmpty() + { + if (mSoulGemPtr.isEmpty()) + return true; + return false; + } + + bool Enchanting::itemEmpty() + { + if(mOldItemPtr.isEmpty()) + return true; + return false; + } +} diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp new file mode 100644 index 0000000000..1daf34c6d1 --- /dev/null +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -0,0 +1,41 @@ +#ifndef GAME_MWMECHANICS_ENCHANTING_H +#define GAME_MWMECHANICS_ENCHANTING_H +#include +#include "../mwworld/ptr.hpp" +#include +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +namespace MWMechanics +{ + class Enchanting + { + + MWWorld::Ptr mOldItemPtr; + MWWorld::Ptr mSoulGemPtr; + MWWorld::Ptr mEnchanter; + const MWWorld::Ptr *mNewItemPtr; + int mEnchantType; + + ESM::EffectList mEffectList; + ESM::Enchantment mEnchantment; + + std::string mNewItemName; + std::string mObjectType; + std::string mOldItemId; + public: + Enchanting(MWWorld::Ptr enchanter); + void setOldItem(MWWorld::Ptr oldItem); + void setNewItemName(std::string s); + void setEffect(ESM::EffectList effectList); + void setSoulGem(MWWorld::Ptr soulGem); + void create(); + void nextEnchantType(); + int getEnchantType(); + int getEnchantCost(); + int getMaxEnchantValue(); + int getGemCharge(); + bool soulEmpty(); + bool itemEmpty(); + }; +} +#endif diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index cc20aeda75..28aa14e8e6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -241,6 +241,11 @@ namespace MWWorld return ""; } + MWWorld::Ptr Class::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + throw std::runtime_error ("class can't be enchanted"); + } + MWWorld::Ptr Class::copyToCellImpl(const Ptr &ptr, CellStore &cell) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 77c29fe489..ae75137f5f 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -231,6 +231,8 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5a23aae972..81b33a55b4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -948,6 +948,31 @@ namespace MWWorld return ret; } + const ESM::Armor *World::createRecord (const ESM::Armor& record) + { + return mStore.insert(record); + } + + const ESM::Weapon *World::createRecord (const ESM::Weapon& record) + { + return mStore.insert(record); + } + + const ESM::Clothing *World::createRecord (const ESM::Clothing& record) + { + return mStore.insert(record); + } + + const ESM::Enchantment *World::createRecord (const ESM::Enchantment& record) + { + return mStore.insert(record); + } + + const ESM::Book *World::createRecord (const ESM::Book& record) + { + return mStore.insert(record); + } + void World::update (float duration, bool paused) { mWeatherManager->update (duration); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 526e68a77a..ea318299f2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -272,25 +272,44 @@ namespace MWWorld ///< \return Resulting mode virtual const ESM::Potion *createRecord (const ESM::Potion& record); - ///< Create a new recrod (of type potion) in the ESM store. + ///< Create a new record (of type potion) in the ESM store. /// \return pointer to created record virtual const ESM::Spell *createRecord (const ESM::Spell& record); - ///< Create a new recrod (of type spell) in the ESM store. + ///< Create a new record (of type spell) in the ESM store. /// \return pointer to created record virtual const ESM::Class *createRecord (const ESM::Class& record); - ///< Create a new recrod (of type class) in the ESM store. + ///< Create a new record (of type class) in the ESM store. /// \return pointer to created record virtual const ESM::Cell *createRecord (const ESM::Cell& record); - ///< Create a new recrod (of type cell) in the ESM store. + ///< Create a new record (of type cell) in the ESM store. /// \return pointer to created record virtual const ESM::NPC *createRecord(const ESM::NPC &record); - ///< Create a new recrod (of type npc) in the ESM store. + ///< Create a new record (of type npc) in the ESM store. /// \return pointer to created record + virtual const ESM::Armor *createRecord (const ESM::Armor& record); + ///< Create a new record (of type armor) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Weapon *createRecord (const ESM::Weapon& record); + ///< Create a new record (of type weapon) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Clothing *createRecord (const ESM::Clothing& record); + ///< Create a new record (of type clothing) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record); + ///< Create a new record (of type enchantment) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Book *createRecord (const ESM::Book& record); + ///< Create a new record (of type book) in the ESM store. + /// \return pointer to created record virtual void update (float duration, bool paused); From eb88463b9419339bc0ba2bd8e55c16cc6b736af4 Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 28 Mar 2013 23:39:20 +0100 Subject: [PATCH 0802/1483] Some enchanting fixes --- apps/openmw/mwclass/armor.cpp | 13 +++++++------ apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 13 +++++++------ apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 13 +++++++------ apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 13 +++++++------ apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwmechanics/enchanting.cpp | 4 ++-- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 11 files changed, 36 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 02ed743dff..a691365747 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -274,18 +274,19 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Armor::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESM::Armor oldItem = *store.get().find(ptr.getCellRef().mRefID); - ESM::Armor newItem = oldItem; + MWWorld::LiveCellRef *ref = + ptr.get(); + + ESM::Armor newItem = *ref->mBase; newItem.mId=""; newItem.mName=newName; newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return ref.getPtr(); + MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return mref.getPtr(); } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 2c79321bb2..e987c48010 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9714bc06e7..5e73dcfd43 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -148,19 +148,20 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Book::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESM::Book oldItem = *store.get().find(ptr.getCellRef().mRefID); - ESM::Book newItem = oldItem; + MWWorld::LiveCellRef *ref = + ptr.get(); + + ESM::Book newItem = *ref->mBase; newItem.mId=""; newItem.mName=newName; newItem.mData.mIsScroll = 1; newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return ref.getPtr(); + MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return mref.getPtr(); } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 950f2be413..b27ae78cee 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 813746fea2..cfef27c422 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -222,18 +222,19 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Clothing::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESM::Clothing oldItem = *store.get().find(ptr.getCellRef().mRefID); - ESM::Clothing newItem = oldItem; + MWWorld::LiveCellRef *ref = + ptr.get(); + + ESM::Clothing newItem = *ref->mBase; newItem.mId=""; newItem.mName=newName; newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return ref.getPtr(); + MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return mref.getPtr(); } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index e705c113bf..d929824ffd 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 79ed66a501..b17481f188 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -362,18 +362,19 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Weapon::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESM::Weapon oldItem = *store.get().find(ptr.getCellRef().mRefID); - ESM::Weapon newItem = oldItem; + MWWorld::LiveCellRef *ref = + ptr.get(); + + ESM::Weapon newItem = *ref->mBase; newItem.mId=""; newItem.mName=newName; newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return ref.getPtr(); + MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return mref.getPtr(); } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 24da3fe64a..561f2403f2 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d3352226b1..2d90f62b05 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -62,8 +62,8 @@ namespace MWMechanics MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobj.getCellRef().mRefID); MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - mOldItemPtr.getRefData().setCount(0); - mSoulGemPtr.getRefData().setCount(0); + mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); + mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); } void Enchanting::nextEnchantType() diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 28aa14e8e6..88f9d75505 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -241,7 +241,7 @@ namespace MWWorld return ""; } - MWWorld::Ptr Class::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index ae75137f5f..2c4034616e 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -231,7 +231,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; From cc8f7f238ef5a620e4103dd58c06d7aa09cc3e96 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 29 Mar 2013 00:55:29 +0100 Subject: [PATCH 0803/1483] Enchanted item base ptr fix --- apps/openmw/mwmechanics/enchanting.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 2d90f62b05..a8e23ed1fc 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -60,6 +60,7 @@ namespace MWMechanics MWWorld::Ptr newobj = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobj.getCellRef().mRefID); + newobj.mPtr = mOldItemPtr.mPtr; MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); From c5f05564511769974dffa0b7097b2072b605ce86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Mar 2013 20:57:33 -0700 Subject: [PATCH 0804/1483] Handle light linear/quadratic settings --- apps/openmw/mwrender/objects.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 23d35c65f0..892b30ca14 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -271,16 +271,11 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre info.time = Ogre::Math::RangeRandom(-500, +500); info.phase = Ogre::Math::RangeRandom(-500, +500); - // changed to linear to look like morrowind - bool quadratic = false; - /* - if (!lightOutQuadInLin) - quadratic = lightQuadratic; + bool quadratic; + if (!lightOutQuadInLin()) + quadratic = lightQuadratic(); else - { quadratic = !info.interior; - } - */ if (!quadratic) { From e7684c4677c610c00c0b155e362194724dbb58fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 29 Mar 2013 09:04:02 +0100 Subject: [PATCH 0805/1483] some random cleanup --- apps/openmw/mwrender/objects.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 892b30ca14..5cf4abdf77 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -1,5 +1,7 @@ #include "objects.hpp" +#include + #include #include #include @@ -271,11 +273,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre info.time = Ogre::Math::RangeRandom(-500, +500); info.phase = Ogre::Math::RangeRandom(-500, +500); - bool quadratic; - if (!lightOutQuadInLin()) - quadratic = lightQuadratic(); - else - quadratic = !info.interior; + bool quadratic = lightOutQuadInLin() ? !info.interior : lightQuadratic(); if (!quadratic) { @@ -286,7 +284,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre else { float r = radius * lightQuadraticRadiusMult(); - float attenuation = lightQuadraticValue() / pow(r, 2); + float attenuation = lightQuadraticValue() / std::pow(r, 2); light->setAttenuation(r*10, 0, 0, attenuation); } From 86275e5bd4f0df24bb95d00abc0bace49d1383fa Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 29 Mar 2013 12:00:09 +0100 Subject: [PATCH 0806/1483] Some enchanting fixes --- apps/openmw/mwclass/armor.cpp | 6 ++---- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 6 ++---- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 6 ++---- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 6 ++---- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 1 + apps/openmw/mwmechanics/enchanting.cpp | 16 +++++++++------- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 12 files changed, 24 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a691365747..b29cbb3d11 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,7 +16,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwworld/manualref.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -274,7 +273,7 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -285,8 +284,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return mref.getPtr(); + return record->mId; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index e987c48010..0c32015a35 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 5e73dcfd43..644561e52b 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -11,7 +11,6 @@ #include "../mwworld/actionread.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" -#include "../mwworld/manualref.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -148,7 +147,7 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -160,8 +159,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return mref.getPtr(); + return record->mId; } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index b27ae78cee..c17d4255b1 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index cfef27c422..8f29a2084d 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -14,7 +14,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwworld/manualref.hpp" #include "../mwgui/tooltips.hpp" @@ -222,7 +221,7 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -233,8 +232,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return mref.getPtr(); + return record->mId; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index d929824ffd..4457e79fb6 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index b17481f188..302dc47daa 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -14,7 +14,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwworld/manualref.hpp" #include "../mwgui/tooltips.hpp" @@ -362,7 +361,7 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -373,8 +372,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return mref.getPtr(); + return record->mId; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 561f2403f2..533f32f592 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 5c31a32669..6114bd4649 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -254,6 +254,7 @@ namespace MWGui mEnchanting.setEffect(mEffectList); mEnchanting.create(); + mWindowManager.messageBox ("#{sEnchantmentMenu12}", std::vector()); mWindowManager.removeGuiMode (GM_Enchanting); } } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index a8e23ed1fc..4ef20a5e52 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -47,6 +47,9 @@ namespace MWMechanics void Enchanting::create() { + mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); + mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + mEnchantment.mData.mCharge = getGemCharge(); if(mEnchantType==3) { @@ -57,14 +60,13 @@ namespace MWMechanics mEnchantment.mEffects = mEffectList; const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); - MWWorld::Ptr newobj = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + std::string newobjId = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobj.getCellRef().mRefID); - newobj.mPtr = mOldItemPtr.mPtr; - MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - - mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); - mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobjId); + MWWorld::Ptr newobjPtr = ref.getPtr(); + MWWorld::Ptr result = mOldItemPtr; + result.mPtr = newobjPtr.mPtr; + MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (result); } void Enchanting::nextEnchantType() diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 88f9d75505..4af0869a31 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -241,7 +241,7 @@ namespace MWWorld return ""; } - MWWorld::Ptr Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 2c4034616e..56189dafde 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -231,7 +231,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; From a39c129954ea7cfb318f32d14644212e648a1aed Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 Mar 2013 19:53:52 +0100 Subject: [PATCH 0807/1483] Clamp individual light attenuation at 1 --- files/materials/objects.shader | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index ae589a05be..c8616e9d1e 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -146,11 +146,11 @@ #if VERTEXCOLOR_MODE == 2 lightResult.xyz += colour.xyz * lightDiffuse[@shIterator].xyz - * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) * max(dot(viewNormal.xyz, lightDir), 0); #else lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz - * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) * max(dot(viewNormal.xyz, lightDir), 0); #endif From 5e7e9fd26aa2f48687e843d47ab287161b1ed82a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 Mar 2013 20:21:37 +0100 Subject: [PATCH 0808/1483] Properly calculate light activation range --- apps/openmw/mwrender/objects.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 5cf4abdf77..50c0210649 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -275,17 +275,23 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre bool quadratic = lightOutQuadInLin() ? !info.interior : lightQuadratic(); + // with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero, + // so we ignore lights if their attenuation falls below this factor. + const float threshold = 0.03; + if (!quadratic) { float r = radius * lightLinearRadiusMult(); float attenuation = lightLinearValue() / r; - light->setAttenuation(r*10, 0, attenuation, 0); + float activationRange = 1 / (threshold * attenuation); + light->setAttenuation(activationRange, 0, attenuation, 0); } else { float r = radius * lightQuadraticRadiusMult(); float attenuation = lightQuadraticValue() / std::pow(r, 2); - light->setAttenuation(r*10, 0, 0, attenuation); + float activationRange = std::sqrt(1 / (threshold * attenuation)); + light->setAttenuation(activationRange, 0, 0, attenuation); } // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node From 35a6ca010ae0ff99b0c3e0cae5477ccfe5f29d3a Mon Sep 17 00:00:00 2001 From: vorenon Date: Fri, 29 Mar 2013 20:43:17 +0100 Subject: [PATCH 0809/1483] Adjusted textbox height in race menu --- files/mygui/openmw_chargen_race.layout | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index c0b04618ed..aaa5b4b502 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + From f93cefa201e1e3cf194011e45dbe71c24e822ce5 Mon Sep 17 00:00:00 2001 From: vorenon Date: Fri, 29 Mar 2013 21:26:40 +0100 Subject: [PATCH 0810/1483] Changed Y position of the textboxes --- files/mygui/openmw_chargen_race.layout | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index aaa5b4b502..a27d271917 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + From a49e52454108a591e87431797335cae83c8338c5 Mon Sep 17 00:00:00 2001 From: vorenon Date: Sat, 30 Mar 2013 03:07:34 +0100 Subject: [PATCH 0811/1483] Reduced width of textboxes in race menu The width of the text box was too large and MyGui didn't align the texts properly. Fixed with the help of the MyGui layout editor. --- files/mygui/openmw_chargen_race.layout | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index a27d271917..c569abb863 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + From 04673b2f14f2572e9b2a6d5d98c066f3b778d3b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 12:54:20 +0100 Subject: [PATCH 0812/1483] Don't enchant if the enchantment value is too high for the item --- apps/openmw/mwgui/enchantingdialog.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 6114bd4649..536dafc01a 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -158,7 +158,7 @@ namespace MWGui if(mEnchanting.getGemCharge()==0) { - mWindowManager.messageBox ("#{sNotifyMessage32}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage32}"); return; } @@ -222,31 +222,37 @@ namespace MWGui { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage30}"); return; } if (mName->getCaption ().empty()) { - mWindowManager.messageBox ("#{sNotifyMessage10}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage10}"); return; } if (boost::lexical_cast(mPrice->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage18}"); return; } if (mEnchanting.soulEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage52}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage52}"); return; } if (mEnchanting.itemEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage11}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage11}"); + return; + } + + if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue()) + { + mWindowManager.messageBox ("#{sNotifyMessage29}"); return; } @@ -254,7 +260,7 @@ namespace MWGui mEnchanting.setEffect(mEffectList); mEnchanting.create(); - mWindowManager.messageBox ("#{sEnchantmentMenu12}", std::vector()); + mWindowManager.messageBox ("#{sEnchantmentMenu12}"); mWindowManager.removeGuiMode (GM_Enchanting); } } From e7af718b55a8a436ddc950bd47a0ebfb4a7a0e9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 12:56:37 +0100 Subject: [PATCH 0813/1483] Remove unnecessary WindowManager::messageBox arguments --- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 12 ++++++------ apps/openmw/mwgui/container.cpp | 6 +++--- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 4 ++-- apps/openmw/mwgui/settingswindow.cpp | 4 ++-- apps/openmw/mwgui/spellcreationdialog.cpp | 12 ++++++------ apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/text_input.cpp | 4 ++-- apps/openmw/mwgui/tradewindow.cpp | 10 +++++----- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/npcstats.cpp | 4 ++-- apps/openmw/mwscript/containerextensions.cpp | 4 ++-- apps/openmw/mwworld/actionequip.cpp | 6 +++--- apps/openmw/mwworld/failedaction.cpp | 2 +- 18 files changed, 41 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index a2d75131eb..4ee95b96e1 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -115,7 +115,7 @@ namespace MWClass if (needKey && hasKey) { - MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}"); ptr.getCellRef().mLockLevel = 0; // using a key disarms the trap ptr.getCellRef().mTrap = ""; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index fb63299397..163cf02775 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -98,7 +98,7 @@ namespace MWClass if (needKey && hasKey) { - MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}"); ptr.getCellRef().mLockLevel = 0; // using a key disarms the trap ptr.getCellRef().mTrap = ""; diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index fce6126001..ca7f1b913a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -77,40 +77,40 @@ namespace MWGui if (result == MWMechanics::Alchemy::Result_NoName) { - mWindowManager.messageBox("#{sNotifyMessage37}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage37}"); return; } // check if mortar & pestle is available (always needed) if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle) { - mWindowManager.messageBox("#{sNotifyMessage45}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage45}"); return; } // make sure 2 or more ingredients were selected if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients) { - mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage6a}"); return; } if (result == MWMechanics::Alchemy::Result_NoEffects) { - mWindowManager.messageBox("#{sNotifyMessage8}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); return; } if (result == MWMechanics::Alchemy::Result_Success) { - mWindowManager.messageBox("#{sPotionSuccess}", std::vector()); + mWindowManager.messageBox("#{sPotionSuccess}"); MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f); } else if (result == MWMechanics::Alchemy::Result_RandomFailure) { // potion failed - mWindowManager.messageBox("#{sNotifyMessage8}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 0a674ba82c..98d818638a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -150,7 +150,7 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) { // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog4}", std::vector()); + messageBox("#{sBarterDialog4}"); return; } } @@ -294,7 +294,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage2}", std::vector()); + messageBox("#{sContentsMessage2}"); return; } @@ -318,7 +318,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) object.getRefData().setCount(origCount); // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage3}", std::vector()); + messageBox("#{sContentsMessage3}"); return; } diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index f0a3858084..67620d49da 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -162,7 +162,7 @@ namespace MWGui MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); if (mSpentAttributes.size() < 3) - MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage36}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage36}"); else { // increase attributes diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 6d51420f01..5ea13fb0d7 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -291,7 +291,7 @@ namespace MWGui if (item.getRefData ().getCount() == 0) { MWBase::Environment::get().getWindowManager ()->messageBox ( - "#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item), std::vector()); + "#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item)); return; } @@ -317,7 +317,7 @@ namespace MWGui if (item.getRefData ().getCount() == 0) { MWBase::Environment::get().getWindowManager ()->messageBox ( - "#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item), std::vector()); + "#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item)); return; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 04856c3ed9..58754472dd 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -362,7 +362,7 @@ namespace MWGui { std::string msg = "This resolution is not supported in Fullscreen mode. Please select a resolution from the list."; MWBase::Environment::get().getWindowManager()-> - messageBox(msg, std::vector()); + messageBox(msg); _sender->castType()->setCaption(off); } else @@ -593,7 +593,7 @@ namespace MWGui static_cast(_sender)->setCaptionWithReplacing("#{sNone}"); - MWBase::Environment::get().getWindowManager ()->messageBox ("#{sControlsMenu3}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox ("#{sControlsMenu3}"); MWBase::Environment::get().getWindowManager ()->disallowMouse(); MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index ea91ac278f..592063a761 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -310,25 +310,25 @@ namespace MWGui { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage30}"); return; } if (mNameEdit->getCaption () == "") { - mWindowManager.messageBox ("#{sNotifyMessage10}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage10}"); return; } if (mMagickaCost->getCaption() == "0") { - mWindowManager.messageBox ("#{sEnchantmentMenu8}", std::vector()); + mWindowManager.messageBox ("#{sEnchantmentMenu8}"); return; } if (boost::lexical_cast(mPriceLabel->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage18}"); return; } @@ -517,7 +517,7 @@ namespace MWGui { if (mEffects.size() >= 8) { - MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage28}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage28}"); return; } @@ -528,7 +528,7 @@ namespace MWGui { if (it->mEffectID == effectId) { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}"); return; } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 50691d5540..d7fb0e1bcd 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -404,7 +404,7 @@ namespace MWGui if (spell->mData.mFlags & ESM::Spell::F_Always || spell->mData.mType == ESM::Spell::ST_Power) { - mWindowManager.messageBox("#{sDeleteSpellError}", std::vector()); + mWindowManager.messageBox("#{sDeleteSpellError}"); } else { diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 9265cadf94..ee9144be68 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -50,7 +50,7 @@ void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) { if (mTextEdit->getCaption() == "") { - mWindowManager.messageBox ("#{sNotifyMessage37}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage37}"); MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); } else @@ -61,7 +61,7 @@ void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) { if (mTextEdit->getCaption() == "") { - mWindowManager.messageBox ("#{sNotifyMessage37}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage37}"); MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); } else diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f84a0abc88..307533d91a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -181,7 +181,7 @@ namespace MWGui { // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog11}", std::vector()); + messageBox("#{sBarterDialog11}"); return; } @@ -190,7 +190,7 @@ namespace MWGui { // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog1}", std::vector()); + messageBox("#{sBarterDialog1}"); return; } @@ -199,7 +199,7 @@ namespace MWGui { // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog2}", std::vector()); + messageBox("#{sBarterDialog2}"); return; } @@ -209,7 +209,7 @@ namespace MWGui if (mPtr.getTypeName() != typeid(ESM::NPC).name()) { MWBase::Environment::get().getWindowManager()-> - messageBox("#{sNotifyMessage9}", std::vector()); + messageBox("#{sNotifyMessage9}"); return; } @@ -245,7 +245,7 @@ namespace MWGui if(roll > x) //trade refused { MWBase::Environment::get().getWindowManager()-> - messageBox("#{sNotifyMessage9}", std::vector()); + messageBox("#{sNotifyMessage9}"); int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt(); MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterFailDisposition); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index ba39ee601c..601b44d6c9 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -129,7 +129,7 @@ namespace MWGui MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mPtr).getNpcStats (mPtr); if (npcStats.getSkill (skillId).getBase () <= pcStats.getSkill (skillId).getBase ()) { - mWindowManager.messageBox ("#{sServiceTrainingWords}", std::vector()); + mWindowManager.messageBox ("#{sServiceTrainingWords}"); return; } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index df8a52456c..09eb5c914e 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -83,7 +83,7 @@ namespace MWGui if (canRest == 2) { // resting underwater or mid-air not allowed - mWindowManager.messageBox ("#{sNotifyMessage1}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage1}"); mWindowManager.popGuiMode (); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1480b3182e..c8d87b425c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -256,7 +256,7 @@ namespace MWMechanics if(MWWorld::Class::get(iter->first).isEssential(iter->first)) MWBase::Environment::get().getWindowManager()->messageBox( - "#{sKilledEssential}", std::vector()); + "#{sKilledEssential}"); } } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 26c4c8e9ac..51e23d16ea 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -221,12 +221,12 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") % static_cast (base); - MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox(message.str()); if (mLevelProgress >= 10) { // levelup is possible now - MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}"); } getSkill (skillIndex).setBase (base); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 81639b5be9..1154b06c6c 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -83,7 +83,7 @@ namespace MWScript msgBox = boost::str(boost::format(msgBox) % count % itemName); } - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox(msgBox); } } }; @@ -179,7 +179,7 @@ namespace MWScript } if (numRemoved > 0) - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox(msgBox); } } }; diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index eb2ae9dca7..afbb505f22 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -62,7 +62,7 @@ namespace MWWorld if((*itr).mPart == ESM::PRT_Head) { if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); allow = false; break; @@ -90,12 +90,12 @@ namespace MWWorld if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) { if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); } else // It's boots { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); } } break; diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index ec763dba01..1db00ad06c 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -15,7 +15,7 @@ namespace MWWorld { if ( actor.getRefData().getHandle()=="player" && !(message.empty())) { - MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); + MWBase::Environment::get().getWindowManager() ->messageBox(message); } } } From 51204f098e77b7fc7767956045e1625eef7dbd84 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 15:51:07 +0100 Subject: [PATCH 0814/1483] Added soulgem dialog; made interactive message boxes not close the previous UI --- apps/openmw/CMakeLists.txt | 4 +-- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwclass/misc.cpp | 10 ++++++++ apps/openmw/mwclass/misc.hpp | 4 +++ apps/openmw/mwgui/enchantingdialog.cpp | 5 ++++ apps/openmw/mwgui/enchantingdialog.hpp | 1 + apps/openmw/mwgui/messagebox.cpp | 21 ++++++++------- apps/openmw/mwgui/messagebox.hpp | 9 ++++++- apps/openmw/mwgui/mode.hpp | 4 +-- apps/openmw/mwgui/soulgemdialog.cpp | 34 +++++++++++++++++++++++++ apps/openmw/mwgui/soulgemdialog.hpp | 28 ++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 29 +++++++++++++-------- apps/openmw/mwgui/windowmanagerimp.hpp | 7 +++++ apps/openmw/mwinput/inputmanagerimp.cpp | 8 +++--- apps/openmw/mwworld/actionsoulgem.cpp | 21 +++++++++++++++ apps/openmw/mwworld/actionsoulgem.hpp | 19 ++++++++++++++ 16 files changed, 177 insertions(+), 30 deletions(-) create mode 100644 apps/openmw/mwgui/soulgemdialog.cpp create mode 100644 apps/openmw/mwgui/soulgemdialog.hpp create mode 100644 apps/openmw/mwworld/actionsoulgem.cpp create mode 100644 apps/openmw/mwworld/actionsoulgem.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9b1e5a02fe..41f56f9931 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair repair + merchantrepair repair soulgemdialog ) add_openmw_dir (mwdialogue @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair + esmstore store recordcmp fallback actionrepair actionsoulgem ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 6760c89d07..58897dc740 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -237,10 +237,13 @@ namespace MWBase virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; + virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; virtual void startRepair(MWWorld::Ptr actor) = 0; virtual void startRepairItem(MWWorld::Ptr item) = 0; + virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; + virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index b971fa6f34..b8a928becb 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -15,6 +15,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/actionsoulgem.hpp" #include "../mwgui/tooltips.hpp" @@ -233,4 +234,13 @@ namespace MWClass } return newPtr; } + + boost::shared_ptr Miscellaneous::use (const MWWorld::Ptr& ptr) const + { + if (ptr.getCellRef().mSoul == "") + return boost::shared_ptr(new MWWorld::NullAction()); + else + return boost::shared_ptr(new MWWorld::ActionSoulgem(ptr)); + } + } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index a5a79a8f6d..12a50af19d 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -49,6 +49,10 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 536dafc01a..ef124bb430 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -92,6 +92,11 @@ namespace MWGui startEditing (); } + void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) + { + /// \todo + } + void EnchantingDialog::onReferenceUnavailable () { mWindowManager.removeGuiMode (GM_Dialogue); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 60445a8dc3..347b37e908 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -22,6 +22,7 @@ namespace MWGui virtual void open(); void startEnchanting(MWWorld::Ptr actor); + void startSelfEnchanting(MWWorld::Ptr soulgem); protected: virtual void onReferenceUnavailable(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index b8a34c457e..46663b67a5 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -3,6 +3,7 @@ #include "messagebox.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/inputmanager.hpp" using namespace MWGui; @@ -62,7 +63,8 @@ void MessageBoxManager::onFrame (float frameDuration) if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { delete mInterMessageBoxe; mInterMessageBoxe = NULL; - mWindowManager->removeGuiMode(GM_InterMessageBox); + MWBase::Environment::get().getInputManager()->changeInputMode( + MWBase::Environment::get().getWindowManager()->isGuiMode()); } } @@ -90,11 +92,8 @@ void MessageBoxManager::createMessageBox (const std::string& message) bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) { - /// \todo Don't write this kind of error message to cout. Either discard the old message box - /// silently or throw an exception. if(mInterMessageBoxe != NULL) { - std::cout << "there is a MessageBox already" << std::endl; - return false; + throw std::runtime_error("There is a message box already"); } mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); @@ -139,7 +138,8 @@ void MessageBoxManager::setMessageBoxSpeed (int speed) void MessageBoxManager::enterPressed () { - mInterMessageBoxe->enterPressed(); + if(mInterMessageBoxe != NULL) + mInterMessageBoxe->enterPressed(); } int MessageBoxManager::readPressedButton () @@ -213,10 +213,12 @@ int MessageBox::getHeight () InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : Layout("openmw_interactive_messagebox.layout") + : WindowModal("openmw_interactive_messagebox.layout", *MWBase::Environment::get().getWindowManager()) , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { + WindowModal::open(); + int fixedWidth = 500; int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 20; // padding between the text-widget und the button-widget @@ -232,7 +234,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan getWidget(mButtonsWidget, "buttons"); mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->addText(message); + mMessageWidget->setCaptionWithReplacing(message); MyGUI::IntSize textSize = mMessageWidget->getTextSize(); @@ -252,7 +254,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan std::string("MW_Button"), dummyCoord, MyGUI::Align::Default); - button->setCaption(*it); + button->setCaptionWithReplacing(*it); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); @@ -399,6 +401,7 @@ void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) if(*button == pressed) { mButtonPressed = index; + mMessageBoxManager.onButtonPressed(mButtonPressed); return; } index++; diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 149aa7e7f1..859e1806a7 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -44,6 +44,13 @@ namespace MWGui void enterPressed(); int readPressedButton (); + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; + + // Note: this delegate unassigns itself after it was fired, i.e. works once. + EventHandle_Int eventButtonPressed; + + void onButtonPressed(int button) { eventButtonPressed(button); eventButtonPressed.clear(); } + MWBase::WindowManager *mWindowManager; private: @@ -73,7 +80,7 @@ namespace MWGui int mNextBoxPadding; }; - class InteractiveMessageBox : public OEngine::GUI::Layout + class InteractiveMessageBox : public WindowModal { public: InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons); diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 4091f47acc..e9b01395f0 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -5,6 +5,7 @@ namespace MWGui { enum GuiMode { + GM_None, GM_Settings, // Settings window GM_Inventory, // Inventory mode GM_Container, @@ -41,9 +42,6 @@ namespace MWGui GM_ClassCreate, GM_Review, - // interactive MessageBox - GM_InterMessageBox, - GM_Loading, GM_LoadingWallpaper, diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp new file mode 100644 index 0000000000..4530a13d0b --- /dev/null +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -0,0 +1,34 @@ +#include "soulgemdialog.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +#include "messagebox.hpp" + +namespace MWGui +{ + + void SoulgemDialog::show(const MWWorld::Ptr &soulgem) + { + mSoulgem = soulgem; + std::vector buttons; + buttons.push_back("#{sRechargeEnchantment}"); + buttons.push_back("#{sMake Enchantment}"); + mManager->createInteractiveMessageBox("#{sDoYouWantTo}", buttons); + mManager->eventButtonPressed += MyGUI::newDelegate(this, &SoulgemDialog::onButtonPressed); + } + + void SoulgemDialog::onButtonPressed(int button) + { + if (button == 0) + { + /// \todo show recharge enchanted item dialog here + } + else + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); + MWBase::Environment::get().getWindowManager()->startSelfEnchanting(mSoulgem); + } + } + +} diff --git a/apps/openmw/mwgui/soulgemdialog.hpp b/apps/openmw/mwgui/soulgemdialog.hpp new file mode 100644 index 0000000000..9aea1f3393 --- /dev/null +++ b/apps/openmw/mwgui/soulgemdialog.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_MWGUI_SOULGEMDIALOG_H +#define OPENMW_MWGUI_SOULGEMDIALOG_H + +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + + class MessageBoxManager; + + class SoulgemDialog + { + public: + SoulgemDialog (MessageBoxManager* manager) + : mManager(manager) {} + + void show (const MWWorld::Ptr& soulgem); + + void onButtonPressed(int button); + + private: + MessageBoxManager* mManager; + MWWorld::Ptr mSoulgem; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 718bb7106e..eadd657871 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -57,6 +57,7 @@ #include "spellicons.hpp" #include "merchantrepair.hpp" #include "repair.hpp" +#include "soulgemdialog.hpp" using namespace MWGui; @@ -94,6 +95,7 @@ WindowManager::WindowManager( , mTrainingWindow(NULL) , mMerchantRepair(NULL) , mRepair(NULL) + , mSoulgemDialog(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -186,6 +188,7 @@ WindowManager::WindowManager( mTrainingWindow = new TrainingWindow(*this); mMerchantRepair = new MerchantRepair(*this); mRepair = new Repair(*this); + mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -253,6 +256,7 @@ WindowManager::~WindowManager() delete mQuickKeysMenu; delete mMerchantRepair; delete mRepair; + delete mSoulgemDialog; delete mCursor; cleanupGarbage(); @@ -316,9 +320,6 @@ void WindowManager::updateVisible() mHud->setVisible(mHudEnabled); - // Mouse is visible whenever we're not in game mode - mCursor->setVisible(isGuiMode()); - bool gameMode = !isGuiMode(); mInputBlocker->setVisible (gameMode); @@ -444,8 +445,6 @@ void WindowManager::updateVisible() case GM_Repair: mRepair->setVisible(true); break; - case GM_InterMessageBox: - break; case GM_Journal: mJournal->setVisible(true); break; @@ -609,7 +608,7 @@ void WindowManager::messageBox (const std::string& message, const std::vectorcreateInteractiveMessageBox(message, buttons); - pushGuiMode(GM_InterMessageBox); + MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); } } @@ -648,6 +647,7 @@ void WindowManager::onDialogueWindowBye() void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); + mToolTips->onFrame(frameDuration); if (mDragAndDrop->mIsOnDragAndDrop) @@ -1033,12 +1033,12 @@ void WindowManager::toggleVisible (GuiWindow wnd) bool WindowManager::isGuiMode() const { - return !mGuiModes.empty(); + return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); } bool WindowManager::isConsoleMode() const { - if (mGuiModes.back()==GM_Console) + if (!mGuiModes.empty() && mGuiModes.back()==GM_Console) return true; return false; } @@ -1046,8 +1046,7 @@ bool WindowManager::isConsoleMode() const MWGui::GuiMode WindowManager::getMode() const { if (mGuiModes.empty()) - throw std::runtime_error ("getMode() called, but there is no active mode"); - + return GM_None; return mGuiModes.back(); } @@ -1143,6 +1142,11 @@ void WindowManager::startEnchanting (MWWorld::Ptr actor) mEnchantingDialog->startEnchanting (actor); } +void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) +{ + mEnchantingDialog->startSelfEnchanting(soulgem); +} + void WindowManager::startTraining(MWWorld::Ptr actor) { mTrainingWindow->startTraining(actor); @@ -1167,3 +1171,8 @@ void WindowManager::changePointer(const std::string &name) { mCursor->onCursorChange(name); } + +void WindowManager::showSoulgemDialog(MWWorld::Ptr item) +{ + mSoulgemDialog->show(item); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 216ab9a6f8..5cf7bae02d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -76,6 +76,7 @@ namespace MWGui class SpellIcons; class MerchantRepair; class Repair; + class SoulgemDialog; class WindowManager : public MWBase::WindowManager { @@ -230,14 +231,19 @@ namespace MWGui virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor); + virtual void startSelfEnchanting(MWWorld::Ptr soulgem); virtual void startTraining(MWWorld::Ptr actor); virtual void startRepair(MWWorld::Ptr actor); virtual void startRepairItem(MWWorld::Ptr item); + virtual void showSoulgemDialog (MWWorld::Ptr item); + virtual void changePointer (const std::string& name); virtual const Translation::Storage& getTranslationDataStorage() const; + void onSoulgemDialogButtonPressed (int button); + private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; @@ -271,6 +277,7 @@ namespace MWGui EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; MerchantRepair* mMerchantRepair; + SoulgemDialog* mSoulgemDialog; Repair* mRepair; Translation::Storage& mTranslationDataStorage; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f49422747f..bd5367dad6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -181,8 +181,7 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - if( MWBase::Environment::get().getWindowManager()->isGuiMode() - && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) { + if( MWBase::Environment::get().getWindowManager()->isGuiMode()) { // Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button MWBase::Environment::get().getWindowManager()->enterPressed(); } @@ -378,7 +377,7 @@ namespace MWInput void InputManager::changeInputMode(bool guiMode) { - // Are we in GUI mode now? + MWBase::Environment::get().getWindowManager()->setMouseVisible(guiMode); if(guiMode) { // Disable mouse look @@ -462,8 +461,7 @@ namespace MWInput bool InputManager::keyPressed( const OIS::KeyEvent &arg ) { if(arg.key == OIS::KC_RETURN - && MWBase::Environment::get().getWindowManager()->isGuiMode() - && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) + && MWBase::Environment::get().getWindowManager()->isGuiMode()) { // Pressing enter when a messagebox is prompting for "ok" will activate the ok button MWBase::Environment::get().getWindowManager()->enterPressed(); diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp new file mode 100644 index 0000000000..6746f692f1 --- /dev/null +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -0,0 +1,21 @@ +#include "actionsoulgem.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +namespace MWWorld +{ + +ActionSoulgem::ActionSoulgem(const Ptr &object) + : Action(false, object) +{ + +} + +void ActionSoulgem::executeImp(const Ptr &actor) +{ + MWBase::Environment::get().getWindowManager()->showSoulgemDialog(getTarget()); +} + + +} diff --git a/apps/openmw/mwworld/actionsoulgem.hpp b/apps/openmw/mwworld/actionsoulgem.hpp new file mode 100644 index 0000000000..0dd5266570 --- /dev/null +++ b/apps/openmw/mwworld/actionsoulgem.hpp @@ -0,0 +1,19 @@ +#ifndef GAME_MWWORLD_ACTIONSOULGEM_H +#define GAME_MWWORLD_ACTIONSOULGEM_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionSoulgem : public Action + { + virtual void executeImp (const MWWorld::Ptr& actor); + + public: + /// @param soulgem to use + ActionSoulgem (const Ptr& object); + }; +} + +#endif From a031c7761943afc38df5e0ea2a595a3cdcc4d90f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 15:56:14 +0100 Subject: [PATCH 0815/1483] Improved enchanting layout --- files/mygui/openmw_enchanting_dialog.layout | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 2549fd26f9..41b8ffa938 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -70,18 +70,18 @@ - + - + - + - - + + From 0079f62180afe7ddf2f9ec3f2d543bca07ee2891 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 16:27:06 +0100 Subject: [PATCH 0816/1483] Gold condition now always checks RefID instead of the name. This is necessary because in the french MW version, the sGold GMST is different from the name of the gold references. --- apps/openmw/mwclass/misc.cpp | 7 ++++- apps/openmw/mwworld/containerstore.cpp | 38 +++++++++++--------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index b971fa6f34..e4d7235cb7 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -158,7 +158,12 @@ namespace MWClass int count = ptr.getRefData().getCount(); - bool isGold = (ref->mBase->mName == store.get().find("sGold")->getString()); + bool isGold = Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100"); + if (isGold && ptr.getCellRef().mGoldValue != 1) count = ptr.getCellRef().mGoldValue; else if (isGold) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index e5b68841b8..a377f2bbbf 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -111,34 +111,28 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if (MWWorld::Class::get(ptr).getName(ptr) == esmStore.get().find("sGold")->getString()) + if (Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100")) { - MWWorld::LiveCellRef *gold = - ptr.get(); + MWWorld::ManualRef ref(esmStore, "Gold_001"); - if (Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_001") - || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_005") - || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_010") - || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_025") - || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_100")) + int count = MWWorld::Class::get(ptr).getValue(ptr) * ptr.getRefData().getCount(); + + ref.getPtr().getRefData().setCount(count); + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - MWWorld::ManualRef ref(esmStore, "Gold_001"); - - int count = MWWorld::Class::get(ptr).getValue(ptr) * ptr.getRefData().getCount(); - - ref.getPtr().getRefData().setCount(count); - for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) + if (Misc::StringUtils::ciEqual((*iter).get()->mRef.mRefID, "gold_001")) { - if (Misc::StringUtils::ciEqual((*iter).get()->mRef.mRefID, "gold_001")) - { - (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); - flagAsModified(); - return iter; - } + (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); + flagAsModified(); + return iter; } - - return addImpl(ref.getPtr()); } + + return addImpl(ref.getPtr()); } // determine whether to stack or not From a723ad8f291c532bbb33fffb4193f44395d4c845 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 16:32:24 +0100 Subject: [PATCH 0817/1483] Don't allow toggling inventory or journal when a modal window is opened --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f49422747f..013c722c02 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -623,6 +623,9 @@ namespace MWInput void InputManager::toggleInventory() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + bool gameMode = !mWindows.isGuiMode(); // Toggle between game mode and inventory mode @@ -660,6 +663,9 @@ namespace MWInput void InputManager::toggleJournal() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + // Toggle between game mode and journal mode bool gameMode = !mWindows.isGuiMode(); From 0f0cc0e3e301c73a80dbe446b31b4d68bd8d5602 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 18:29:21 +0100 Subject: [PATCH 0818/1483] Fix a few gold conditions that I missed, trade window was affected --- apps/openmw/mwclass/misc.cpp | 42 +++++++++++++++---------------- apps/openmw/mwgui/container.cpp | 4 +-- apps/openmw/mwgui/tradewindow.cpp | 5 +++- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index e4d7235cb7..c1639af2b6 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -23,6 +23,18 @@ #include +namespace +{ +bool isGold (const MWWorld::Ptr& ptr) +{ + return Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100"); +} +} + namespace MWClass { void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -109,25 +121,15 @@ namespace MWClass std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - if (ref->mBase->mName == MWBase::Environment::get().getWorld()->getStore().get().find("sGold")->getString()) - { + if (isGold(ptr)) return std::string("Item Gold Up"); - } return std::string("Item Misc Up"); } std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - if (ref->mBase->mName == MWBase::Environment::get().getWorld()->getStore().get().find("sGold")->getString()) - { + if (isGold(ptr)) return std::string("Item Gold Down"); - } return std::string("Item Misc Down"); } @@ -158,19 +160,15 @@ namespace MWClass int count = ptr.getRefData().getCount(); - bool isGold = Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100"); + bool gold = isGold(ptr); - if (isGold && ptr.getCellRef().mGoldValue != 1) + if (gold && ptr.getCellRef().mGoldValue != 1) count = ptr.getCellRef().mGoldValue; - else if (isGold) + else if (gold) count *= ref->mBase->mData.mValue; std::string countString; - if (!isGold) + if (!gold) countString = MWGui::ToolTips::getCountString(count); else // gold displays its count also if it's 1. countString = " (" + boost::lexical_cast(count) + ")"; @@ -186,7 +184,7 @@ namespace MWClass std::string text; - if (!isGold) + if (!gold) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); @@ -210,7 +208,7 @@ namespace MWClass const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - if (MWWorld::Class::get(ptr).getName(ptr) == store.get().find("sGold")->getString()) { + if (isGold(ptr)) { int goldAmount = ptr.getRefData().getCount(); std::string base = "Gold_001"; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 0a674ba82c..36e32c822d 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -144,9 +144,7 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) MWBase::Environment::get().getWorld()->getStore().get(); // the player is trying to sell an item, check if the merchant accepts it - // also, don't allow selling gold (let's be better than Morrowind at this, can we?) - if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object) || - MWWorld::Class::get(object).getName(object) == gmst.find("sGold")->getString()) + if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) { // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f84a0abc88..f474f756df 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -135,7 +135,7 @@ namespace MWGui for (MWWorld::ContainerStoreIterator it = playerStore.begin(); it != playerStore.end(); ++it) { - if (MWWorld::Class::get(*it).getName(*it) == gmst.find("sGold")->getString()) + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) { goldFound = true; gold = *it; @@ -342,6 +342,9 @@ namespace MWGui bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item) { + if (Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001")) + return false; + int services = 0; if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { From 7dbc779c3aa4b40e4efabe918cc285c587b5d522 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sat, 30 Mar 2013 19:08:42 +0100 Subject: [PATCH 0819/1483] Self-enchanting mechanics --- apps/openmw/mwgui/enchantingdialog.cpp | 22 +++++++++-- apps/openmw/mwmechanics/enchanting.cpp | 55 ++++++++++++++++++++++++-- apps/openmw/mwmechanics/enchanting.hpp | 9 ++++- 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index ef124bb430..7d5d1411f9 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -19,7 +19,6 @@ namespace MWGui : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) , EffectEditorBase(parWindowManager) , mItemSelectionDialog(NULL) - , mEnchanting(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) { getWidget(mName, "NameEdit"); getWidget(mCancelButton, "CancelButton"); @@ -87,6 +86,9 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(actor); + mPtr = actor; startEditing (); @@ -94,7 +96,14 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { - /// \todo + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + mEnchanting.setSelfEnchanting(true); + mEnchanting.setEnchanter(player); + + mPtr = player; + + startEditing(); } void EnchantingDialog::onReferenceUnavailable () @@ -264,8 +273,13 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - mEnchanting.create(); - mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + int result = mEnchanting.create(); + + if(result==1) + mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + else + mWindowManager.messageBox ("#{sNotifyMessage34}"); + mWindowManager.removeGuiMode (GM_Enchanting); } } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 4ef20a5e52..3590ae0f3f 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -3,10 +3,13 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" + +#include "creaturestats.hpp" +#include "npcstats.hpp" + namespace MWMechanics { - Enchanting::Enchanting(MWWorld::Ptr enchanter): - mEnchanter(enchanter), + Enchanting::Enchanting(): mEnchantType(0) {} @@ -45,11 +48,20 @@ namespace MWMechanics mSoulGemPtr=soulGem; } - void Enchanting::create() + int Enchanting::create() { - mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + if(mSelfEnchanting) + { + if(getEnchantChance() (RAND_MAX)*100) + return 0; + + MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); + } + + mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); + mEnchantment.mData.mCharge = getGemCharge(); if(mEnchantType==3) { @@ -67,6 +79,7 @@ namespace MWMechanics MWWorld::Ptr result = mOldItemPtr; result.mPtr = newobjPtr.mPtr; MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (result); + return 1; } void Enchanting::nextEnchantType() @@ -110,6 +123,10 @@ namespace MWMechanics float cost = 0; std::vector mEffects = mEffectList.mList; int i=mEffects.size(); + + /* + Formula from http://www.uesp.net/wiki/Morrowind:Enchant + */ for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { const ESM::MagicEffect* effect = store.get().find(it->mEffectID); @@ -164,4 +181,34 @@ namespace MWMechanics return true; return false; } + + void Enchanting::setSelfEnchanting(bool selfEnchanting) + { + mSelfEnchanting = selfEnchanting; + } + + void Enchanting::setEnchanter(MWWorld::Ptr enchanter) + { + mEnchanter = enchanter; + } + + float Enchanting::getEnchantChance() + { + /* + Formula from http://www.uesp.net/wiki/Morrowind:Enchant + */ + const CreatureStats& creatureStats = MWWorld::Class::get (mEnchanter).getCreatureStats (mEnchanter); + const NpcStats& npcStats = MWWorld::Class::get (mEnchanter).getNpcStats (mEnchanter); + + float chance1 = (npcStats.getSkill (ESM::Skill::Enchant).getModified() + + (0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified()) + + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); + + float chance2 = 2.5 * getEnchantCost(); + if(mEnchantType==3) + { + chance2 *= 2; + } + return (chance1-chance2); + } } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 1daf34c6d1..fffa2c5b20 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -16,6 +16,8 @@ namespace MWMechanics const MWWorld::Ptr *mNewItemPtr; int mEnchantType; + bool mSelfEnchanting; + ESM::EffectList mEffectList; ESM::Enchantment mEnchantment; @@ -23,17 +25,20 @@ namespace MWMechanics std::string mObjectType; std::string mOldItemId; public: - Enchanting(MWWorld::Ptr enchanter); + Enchanting(); + void setEnchanter(MWWorld::Ptr enchanter); + void setSelfEnchanting(bool selfEnchanting); void setOldItem(MWWorld::Ptr oldItem); void setNewItemName(std::string s); void setEffect(ESM::EffectList effectList); void setSoulGem(MWWorld::Ptr soulGem); - void create(); + int create(); void nextEnchantType(); int getEnchantType(); int getEnchantCost(); int getMaxEnchantValue(); int getGemCharge(); + float getEnchantChance(); bool soulEmpty(); bool itemEmpty(); }; From ee5d0277e8729965bbce2efc0e9b4db3448e3cba Mon Sep 17 00:00:00 2001 From: lazydev Date: Sat, 30 Mar 2013 22:18:34 +0400 Subject: [PATCH 0820/1483] fix for #634 --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index cd9908d3df..f7e9529568 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -198,7 +198,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c if (imData.mNumLongs) return select.selectCompare (locals.mLongs[i]); - i -= script->mData.mNumShorts; + i -= script->mData.mNumLongs; return select.selectCompare (locals.mFloats.at (i)); } From e27e53f607550f65c6b7b962fc5151f20b2d7101 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 20:04:05 +0100 Subject: [PATCH 0821/1483] Fix not playable body parts appearing in the race selection menu. --- apps/esmtool/labels.cpp | 4 +- apps/openmw/mwgui/container.cpp | 3 - apps/openmw/mwgui/race.cpp | 138 ++++++++++++++++++++---------- apps/openmw/mwgui/race.hpp | 3 + apps/openmw/mwgui/tradewindow.cpp | 3 - components/esm/loadbody.hpp | 2 +- 6 files changed, 99 insertions(+), 54 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index f08c31003c..3fb1166e8e 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -627,10 +627,10 @@ std::string bodyPartFlags(int flags) std::string properties = ""; if (flags == 0) properties += "[None] "; if (flags & ESM::BodyPart::BPF_Female) properties += "Female "; - if (flags & ESM::BodyPart::BPF_Playable) properties += "Playable "; + if (flags & ESM::BodyPart::BPF_NotPlayable) properties += "NotPlayable "; int unused = (0xFFFFFFFF ^ (ESM::BodyPart::BPF_Female| - ESM::BodyPart::BPF_Playable)); + ESM::BodyPart::BPF_NotPlayable)); if (flags & unused) properties += "Invalid "; properties += str(boost::format("(0x%08X)") % flags); return properties; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 36e32c822d..7836fee16e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -140,9 +140,6 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) if (isInventory()) { - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - // the player is trying to sell an item, check if the merchant accepts it if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) { diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 1436995c53..be693eb2ba 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -19,6 +19,49 @@ using namespace MWGui; using namespace Widgets; +namespace +{ +int wrap(int index, int max) +{ + if (index < 0) + return max - 1; + else if (index >= max) + return 0; + else + return index; +} + +int countParts(const std::string &part, const std::string &race, bool male) +{ + /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string prefix = + "b_n_" + race + ((male) ? "_m_" : "_f_") + part; + + std::string suffix; + suffix.reserve(prefix.size() + 3); + + int count = -1; + do { + ++count; + suffix = "_" + (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + + if (count == 0 && part == "hair") { + count = -1; + do { + ++count; + suffix = (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + } + return count; +} +} + RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) : WindowModal("openmw_chargen_race.layout", parWindowManager) , mGenderIndex(0) @@ -144,45 +187,6 @@ void RaceDialog::setRaceId(const std::string &raceId) updateSpellPowers(); } -int wrap(int index, int max) -{ - if (index < 0) - return max - 1; - else if (index >= max) - return 0; - else - return index; -} - -int countParts(const std::string &part, const std::string &race, bool male) -{ - const MWWorld::Store &store = - MWBase::Environment::get().getWorld()->getStore().get(); - - std::string prefix = - "b_n_" + race + ((male) ? "_m_" : "_f_") + part; - - std::string suffix; - suffix.reserve(prefix.size() + 3); - - int count = -1; - do { - ++count; - suffix = "_" + (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - - if (count == 0 && part == "hair") { - count = -1; - do { - ++count; - suffix = (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - } - return count; -} - void RaceDialog::close() { delete mPreview; @@ -229,28 +233,67 @@ void RaceDialog::onSelectNextGender(MyGUI::Widget*) void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) { - mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); + do + mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); + while (!isFacePlayable()); updatePreview(); } void RaceDialog::onSelectNextFace(MyGUI::Widget*) { - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + do + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + while (!isFacePlayable()); updatePreview(); } void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) { - mHairIndex = wrap(mHairIndex - 1, mHairCount); + do + mHairIndex = wrap(mHairIndex - 1, mHairCount); + while (!isHairPlayable()); updatePreview(); } void RaceDialog::onSelectNextHair(MyGUI::Widget*) { - mHairIndex = wrap(mHairIndex + 1, mHairCount); + do + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isHairPlayable()); updatePreview(); } +bool RaceDialog::isFacePlayable() +{ + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(prefix + "head_" + headIndex) == 0) + return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); +} + +bool RaceDialog::isHairPlayable() +{ + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + if (parts.search(prefix + "hair_" + hairIndex) == 0) + return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); +} + void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) { if (_index == MyGUI::ITEM_NONE) @@ -273,11 +316,16 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) void RaceDialog::recountParts() { + mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); + mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + mFaceIndex = 0; mHairIndex = 0; - mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); - mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + while (!isHairPlayable()) + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isFacePlayable()) + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); } // update widget content diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index efd08f4395..0ca440ad53 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -81,6 +81,9 @@ namespace MWGui void updatePreview(); void recountParts(); + bool isHairPlayable(); + bool isFacePlayable(); + MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; MyGUI::ScrollBar* mHeadRotate; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f474f756df..ab9f3a3101 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -129,9 +129,6 @@ namespace MWGui MWWorld::Ptr gold; MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore(); - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - for (MWWorld::ContainerStoreIterator it = playerStore.begin(); it != playerStore.end(); ++it) { diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index c91bb40bf2..c467b36251 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -33,7 +33,7 @@ struct BodyPart enum Flags { BPF_Female = 1, - BPF_Playable = 2 + BPF_NotPlayable = 2 }; enum MeshType From c8606d2f63d63c8db1cca9838d2f03466587907f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Mar 2013 13:20:51 -0700 Subject: [PATCH 0822/1483] Implement IsWerewolf script function --- apps/openmw/mwscript/docs/vmformat.txt | 4 +++- apps/openmw/mwscript/statsextensions.cpp | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 0f07b4d2e8..7e9827062b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -316,5 +316,7 @@ op 0x20001f9: Drop, explicit reference op 0x20001fa: DropSoulGem op 0x20001fb: DropSoulGem, explicit reference op 0x20001fc: OnDeath +op 0x20001fd: IsWerewolf +op 0x20001fe: IsWerewolf, explicit reference -opcodes 0x20001fd-0x3ffffff unused +opcodes 0x20001ff-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index c5fc9436be..1d321fbbb7 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1046,6 +1046,18 @@ namespace MWScript } }; + template + class OpIsWerewolf : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + runtime.push(MWWorld::Class::get(ptr).getNpcStats(ptr).isWerewolf()); + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -1137,6 +1149,9 @@ namespace MWScript const int opcodeOnDeath = 0x20001fc; + const int opcodeIsWerewolf = 0x20001fd; + const int opcodeIsWerewolfExplicit = 0x20001fe; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -1252,6 +1267,8 @@ namespace MWScript extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath); + + extensions.registerFunction ("iswerewolf", 'l', "", opcodeIsWerewolf, opcodeIsWerewolfExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -1368,6 +1385,9 @@ namespace MWScript interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank); interpreter.installSegment5 (opcodeOnDeath, new OpOnDeath); + + interpreter.installSegment5 (opcodeIsWerewolf, new OpIsWerewolf); + interpreter.installSegment5 (opcodeIsWerewolfExplicit, new OpIsWerewolf); } } } From 63af72c31577454322524c30982f964e4b6cfaa3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Mar 2013 17:31:16 -0700 Subject: [PATCH 0823/1483] Avoid converting to and from quaternions --- apps/openmw/mwrender/renderingmanager.cpp | 34 +++++++++-------------- apps/openmw/mwworld/worldimp.cpp | 4 ++- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1bab676c3c..7c442c6868 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -262,37 +262,29 @@ void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3 ptr.getRefData().getBaseNode()->setScale(scale); } -bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot, bool adjust) +bool RenderingManager::rotateObject(const MWWorld::Ptr &ptr, Ogre::Vector3 &rot, bool adjust) { bool isActive = ptr.getRefData().getBaseNode() != 0; bool isPlayer = isActive && ptr.getRefData().getHandle() == "player"; bool force = true; - + if (isPlayer) force = mPlayer->rotate(rot, adjust); - - MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z); + MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z); if (!isPlayer && isActive) { - Ogre::Quaternion xr(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); - - Ogre::Quaternion xref(Ogre::Radian(-ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yref(Ogre::Radian(-ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - - Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; - - Ogre::Matrix3 mat; - newo.ToRotationMatrix(mat); - Ogre::Radian ax,ay,az; - mat.ToEulerAnglesXYZ(ax,ay,az); - rot.x = -ax.valueRadians(); - rot.y = -ay.valueRadians(); - rot.z = -az.valueRadians(); + if(adjust) + { + const float *objRot = ptr.getRefData().getPosition().rot; + rot.x += objRot[0]; + rot.y += objRot[1]; + rot.z += objRot[2]; + } + Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) * + Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) * + Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); ptr.getRefData().getBaseNode()->setOrientation(newo); } else if(isPlayer) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 75ff6ec830..209e4c4be6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -816,7 +816,9 @@ namespace MWWorld { // rotate physically iff renderer confirm so float *objRot = ptr.getRefData().getPosition().rot; - objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; + objRot[0] = rot.x; + objRot[1] = rot.y; + objRot[2] = rot.z; if (ptr.getRefData().getBaseNode() != 0) { mPhysics->rotateObject(ptr); From af65ecd8415b3504c26b8d9fdb8d713bfef2fa89 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Mar 2013 18:37:40 -0700 Subject: [PATCH 0824/1483] Pass the movement vector in as a parameter to CharacterController::update --- apps/openmw/mwmechanics/activators.cpp | 5 ++++- apps/openmw/mwmechanics/actors.cpp | 3 ++- apps/openmw/mwmechanics/character.cpp | 6 +----- apps/openmw/mwmechanics/character.hpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index b67fcb2164..51fa55f4e4 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -56,7 +56,10 @@ void Activators::update(float duration, bool paused) if(!paused) { for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) - iter->second.update(duration); + { + Ogre::Vector3 movement(0.0f); + iter->second.update(duration, movement); + } } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1480b3182e..a7615311b5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -266,7 +266,8 @@ namespace MWMechanics for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 movement = iter->second.update(duration); + Ogre::Vector3 movement(0.0f); + iter->second.update(duration, movement); mMovement.push_back(std::make_pair(iter->first, movement)); } MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 62958db8d4..5e112d54e5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -168,10 +168,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -Ogre::Vector3 CharacterController::update(float duration) +void CharacterController::update(float duration, Ogre::Vector3 &movement) { - Ogre::Vector3 movement(0.0f); - float speed = 0.0f; if(!(getState() >= CharState_Death1)) { @@ -240,8 +238,6 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); } mSkipAnim = false; - - return movement; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 46f0690e77..8cba49b5ff 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -87,7 +87,7 @@ public: void updatePtr(const MWWorld::Ptr &ptr); - Ogre::Vector3 update(float duration); + void update(float duration, Ogre::Vector3 &movement); void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); From 0ce188b7cc02ef6e1cd49ceb8fd1b5e24cc1d48c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Mar 2013 19:00:46 -0700 Subject: [PATCH 0825/1483] Store the position and rotation in MWMechanics::Movement --- apps/openmw/mwclass/npc.cpp | 9 ++------- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/movement.hpp | 11 +++++++---- apps/openmw/mwworld/player.cpp | 8 ++++---- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index a5319ada07..61d081b4b1 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -368,7 +368,7 @@ namespace MWClass moveSpeed = runSpeed; else moveSpeed = walkSpeed; - if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) + if(getMovementSettings(ptr).mPosition[0] != 0 && getMovementSettings(ptr).mPosition[1] == 0) moveSpeed *= 0.75f; return moveSpeed; @@ -414,12 +414,7 @@ namespace MWClass Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const { - Ogre::Vector3 vector; - vector.x = getMovementSettings(ptr).mLeftRight; - vector.y = getMovementSettings(ptr).mForwardBackward; - vector.z = getMovementSettings(ptr).mUpDown; - - return vector; + return Ogre::Vector3(getMovementSettings(ptr).mPosition); } bool Npc::isEssential (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5e112d54e5..ea9ff7e10c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -175,12 +175,12 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) { const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = MWWorld::Class::get(mPtr); - const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); bool onground = world->isOnGround(mPtr); bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak); + const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); speed = cls.getSpeed(mPtr); /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except diff --git a/apps/openmw/mwmechanics/movement.hpp b/apps/openmw/mwmechanics/movement.hpp index 11eb83151e..6c9a4b7589 100644 --- a/apps/openmw/mwmechanics/movement.hpp +++ b/apps/openmw/mwmechanics/movement.hpp @@ -6,11 +6,14 @@ namespace MWMechanics /// Desired movement for an actor struct Movement { - signed char mLeftRight; // 1: wants to move left, -1: wants to move right - signed char mForwardBackward; // 1:wants to move forward, -1: wants to move backward - signed char mUpDown; + float mPosition[3]; + float mRotation[3]; - Movement() : mLeftRight (0), mForwardBackward (0), mUpDown(0) {} + Movement() + { + mPosition[0] = mPosition[1] = mPosition[2] = 0.0f; + mRotation[0] = mRotation[1] = mRotation[2] = 0.0f; + } }; } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0dc8b37eff..b01b929c46 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -42,14 +42,14 @@ namespace MWWorld if (mAutoMove) value = 1; - MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; + MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[1] = value; } void Player::setLeftRight (int value) { MWWorld::Ptr ptr = getPlayer(); - MWWorld::Class::get (ptr).getMovementSettings (ptr).mLeftRight = value; + MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[0] = value; } void Player::setForwardBackward (int value) @@ -61,14 +61,14 @@ namespace MWWorld if (mAutoMove) value = 1; - MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; + MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[1] = value; } void Player::setUpDown(int value) { MWWorld::Ptr ptr = getPlayer(); - MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value; + MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[2] = value; } void Player::setRunState(bool run) From 466c0086b84eaca4da61b8d3a64e9ba675ebe24a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 00:13:56 -0700 Subject: [PATCH 0826/1483] Use a full Movement to hand off to the world physics update --- apps/openmw/mwbase/world.hpp | 7 ++++++- apps/openmw/mwmechanics/activators.cpp | 4 +++- apps/openmw/mwmechanics/actors.cpp | 3 ++- apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 17 +++++++++++------ apps/openmw/mwmechanics/character.hpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 5 +++-- 7 files changed, 29 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 67d7dda6a6..8eea383eb4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -44,6 +44,11 @@ namespace MWRender class Animation; } +namespace MWMechanics +{ + class Movement; +} + namespace MWWorld { class Fallback; @@ -54,7 +59,7 @@ namespace MWWorld class ESMStore; class RefData; - typedef std::vector > PtrMovementList; + typedef std::vector > PtrMovementList; } namespace MWBase diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 51fa55f4e4..cbc3802995 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -2,6 +2,8 @@ #include +#include "movement.hpp" + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -57,7 +59,7 @@ void Activators::update(float duration, bool paused) { for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) { - Ogre::Vector3 movement(0.0f); + Movement movement; iter->second.update(duration, movement); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a7615311b5..6aae850878 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -17,6 +17,7 @@ #include "../mwbase/windowmanager.hpp" #include "creaturestats.hpp" +#include "movement.hpp" namespace MWMechanics { @@ -266,7 +267,7 @@ namespace MWMechanics for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 movement(0.0f); + Movement movement; iter->second.update(duration, movement); mMovement.push_back(std::make_pair(iter->first, movement)); } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index fc4af8dd63..aabd86dc7a 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -7,6 +7,7 @@ #include #include "character.hpp" +#include "movement.hpp" #include "../mwbase/world.hpp" namespace Ogre diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea9ff7e10c..3bba065ff4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,8 @@ #include +#include "movement.hpp" + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" @@ -168,7 +170,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -void CharacterController::update(float duration, Ogre::Vector3 &movement) +void CharacterController::update(float duration, Movement &movement) { float speed = 0.0f; if(!(getState() >= CharState_Death1)) @@ -190,14 +192,14 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) float x = cls.getJump(mPtr); if(vec.x == 0 && vec.y == 0) - movement.z += x*duration; + movement.mPosition[2] += x*duration; else { /* FIXME: this would be more correct if we were going into a jumping state, * rather than normal walking/idle states. */ //Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); //movement += Ogre::Vector3(lat.x, lat.y, 1.0f) * x * 0.707f * duration; - movement.z += x * 0.707f * duration; + movement.mPosition[2] += x * 0.707f * duration; } //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult; @@ -214,7 +216,7 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); // Apply any forward/backward movement manually - movement.y += vec.y * (speed*duration); + movement.mPosition[1] += vec.y * (speed*duration); } else if(vec.y != 0.0f && speed > 0.0f) { @@ -226,7 +228,7 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true); // Apply any sideways movement manually - movement.x += vec.x * (speed*duration); + movement.mPosition[0] += vec.x * (speed*duration); } else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); @@ -235,7 +237,10 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) if(mAnimation && !mSkipAnim) { mAnimation->setSpeed(speed); - movement += mAnimation->runAnimation(duration); + Ogre::Vector3 moved = mAnimation->runAnimation(duration); + movement.mPosition[0] += moved.x; + movement.mPosition[1] += moved.y; + movement.mPosition[2] += moved.z; } mSkipAnim = false; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8cba49b5ff..61efd0be0e 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -13,6 +13,8 @@ namespace MWRender namespace MWMechanics { +class Movement; + enum CharacterState { CharState_SpecialIdle, CharState_Idle, @@ -87,7 +89,7 @@ public: void updatePtr(const MWWorld::Ptr &ptr); - void update(float duration, Ogre::Vector3 &movement); + void update(float duration, Movement &movement); void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 209e4c4be6..37fa73279e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -13,6 +13,7 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/movement.hpp" #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" @@ -875,13 +876,13 @@ namespace MWWorld player = iter; continue; } - Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, + Ogre::Vector3 vec = mPhysics->move(iter->first, Ogre::Vector3(iter->second.mPosition), duration, !isSwimming(iter->first) && !isFlying(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { - Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, + Ogre::Vector3 vec = mPhysics->move(player->first, Ogre::Vector3(player->second.mPosition), duration, !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } From 13be61812a101d2278234044cf72a4bc5fd27440 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 10:16:02 +0200 Subject: [PATCH 0827/1483] Made the "Unknown class key" exception slightly more helpful --- apps/openmw/mwworld/class.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 876328641a..1eb2f35bd0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -184,10 +184,13 @@ namespace MWWorld const Class& Class::get (const std::string& key) { + if (key.empty()) + throw std::logic_error ("Class::get(): attempting to get an empty key"); + std::map >::const_iterator iter = sClasses.find (key); if (iter==sClasses.end()) - throw std::logic_error ("unknown class key: " + key); + throw std::logic_error ("Class::get(): unknown class key: " + key); return *iter->second; } From 7b02ec411bcb04fb667eda5c509a9b6b33bbe806 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 01:29:24 -0700 Subject: [PATCH 0828/1483] Apply the rotation when updating the character controller --- apps/openmw/mwclass/npc.cpp | 7 ++++++- apps/openmw/mwclass/npc.hpp | 3 +++ apps/openmw/mwmechanics/character.cpp | 5 +++++ apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 61d081b4b1..e3733fe7c0 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -416,7 +416,12 @@ namespace MWClass { return Ogre::Vector3(getMovementSettings(ptr).mPosition); } - + + Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const + { + return Ogre::Vector3(getMovementSettings(ptr).mRotation); + } + bool Npc::isEssential (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 0f61fc8c91..1a10bce6c1 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -96,6 +96,9 @@ namespace MWClass ///< Return desired movement vector (determined based on movement settings, /// stance and stats). + virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3bba065ff4..56de21d274 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -183,6 +183,7 @@ void CharacterController::update(float duration, Movement &movement) bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + const Ogre::Vector3 &rot = cls.getRotationVector(mPtr); speed = cls.getSpeed(mPtr); /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except @@ -232,6 +233,10 @@ void CharacterController::update(float duration, Movement &movement) } else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + + movement.mRotation[0] += rot.x * duration; + movement.mRotation[1] += rot.y * duration; + movement.mRotation[2] += rot.z * duration; } if(mAnimation && !mSkipAnim) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 876328641a..571815d9e6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -142,6 +142,11 @@ namespace MWWorld return Ogre::Vector3 (0, 0, 0); } + Ogre::Vector3 Class::getRotationVector (const Ptr& ptr) const + { + return Ogre::Vector3 (0, 0, 0); + } + std::pair, bool> Class::getEquipmentSlots (const Ptr& ptr) const { return std::make_pair (std::vector(), false); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 012a03bf62..36d7e97db0 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -150,6 +150,9 @@ namespace MWWorld ///< Return desired movement vector (determined based on movement settings, /// stance and stats). + virtual Ogre::Vector3 getRotationVector (const Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + virtual std::pair, bool> getEquipmentSlots (const Ptr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? From 38d19d33d8029ecddfcc1b66f8d5a978e9b8d69e Mon Sep 17 00:00:00 2001 From: lazydev Date: Sat, 30 Mar 2013 22:18:34 +0400 Subject: [PATCH 0829/1483] fix for #634 --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index cd9908d3df..f7e9529568 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -198,7 +198,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c if (imData.mNumLongs) return select.selectCompare (locals.mLongs[i]); - i -= script->mData.mNumShorts; + i -= script->mData.mNumLongs; return select.selectCompare (locals.mFloats.at (i)); } From b6f2b39a2fa0139300009975818a29377b2aaf36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 01:56:38 -0700 Subject: [PATCH 0830/1483] Clear the movement and rotation vector when getting them --- apps/openmw/mwclass/npc.cpp | 14 ++++++++++++-- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e3733fe7c0..cd6b0def11 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -414,12 +414,22 @@ namespace MWClass Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const { - return Ogre::Vector3(getMovementSettings(ptr).mPosition); + MWMechanics::Movement &movement = getMovementSettings(ptr); + Ogre::Vector3 vec(movement.mPosition); + movement.mPosition[0] = 0.0f; + movement.mPosition[1] = 0.0f; + movement.mPosition[2] = 0.0f; + return vec; } Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const { - return Ogre::Vector3(getMovementSettings(ptr).mRotation); + MWMechanics::Movement &movement = getMovementSettings(ptr); + Ogre::Vector3 vec(movement.mRotation); + movement.mRotation[0] = 0.0f; + movement.mRotation[1] = 0.0f; + movement.mRotation[2] = 0.0f; + return vec; } bool Npc::isEssential (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 013c722c02..1d55ff84dd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -288,8 +288,6 @@ namespace MWInput triedToMove = true; mPlayer.setLeftRight (1); } - else - mPlayer.setLeftRight (0); if (actionIsActive(A_MoveForward)) { @@ -303,8 +301,6 @@ namespace MWInput mPlayer.setAutoMove (false); mPlayer.setForwardBackward (-1); } - else - mPlayer.setForwardBackward (0); mPlayer.setSneak(actionIsActive(A_Sneak)); @@ -313,8 +309,6 @@ namespace MWInput mPlayer.setUpDown (1); triedToMove = true; } - else - mPlayer.setUpDown (0); if (mAlwaysRunActive) mPlayer.setRunState(!actionIsActive(A_Run)); From 18e8ff7198b0b7247c3ba0fae5101ca0f653e106 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 02:24:44 -0700 Subject: [PATCH 0831/1483] Actually rotate the object when updating physics --- apps/openmw/mwworld/worldimp.cpp | 20 ++++++++++++++------ apps/openmw/mwworld/worldimp.hpp | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 37fa73279e..ae0e02c8c9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -806,13 +806,8 @@ namespace MWWorld mPhysics->scaleObject(ptr); } - void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) + void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) { - Ogre::Vector3 rot; - rot.x = Ogre::Degree(x).valueRadians(); - rot.y = Ogre::Degree(y).valueRadians(); - rot.z = Ogre::Degree(z).valueRadians(); - if (mRendering->rotateObject(ptr, rot, adjust)) { // rotate physically iff renderer confirm so @@ -827,6 +822,14 @@ namespace MWWorld } } + void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) + { + rotateObjectImp(ptr, Ogre::Vector3(Ogre::Degree(x).valueRadians(), + Ogre::Degree(y).valueRadians(), + Ogre::Degree(z).valueRadians()), + adjust); + } + void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) { copyObjectToCell(ptr,Cell,pos); @@ -876,12 +879,17 @@ namespace MWWorld player = iter; continue; } + + rotateObjectImp(iter->first, Ogre::Vector3(iter->second.mRotation), true); + Ogre::Vector3 vec = mPhysics->move(iter->first, Ogre::Vector3(iter->second.mPosition), duration, !isSwimming(iter->first) && !isFlying(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { + rotateObjectImp(player->first, Ogre::Vector3(player->second.mRotation), true); + Ogre::Vector3 vec = mPhysics->move(player->first, Ogre::Vector3(player->second.mPosition), duration, !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8554d904a4..8cff50bd16 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -90,6 +90,8 @@ namespace MWWorld int getDaysPerMonth (int month) const; + void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust); + bool moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return true if the active cell (cell player is in) changed From 13c098266cbe17e49917ff3b1306765b9f853452 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 02:57:22 -0700 Subject: [PATCH 0832/1483] Pass player rotation through the movement settings --- apps/openmw/mwinput/inputmanagerimp.cpp | 8 ++++---- apps/openmw/mwworld/player.cpp | 16 ++++++++++++++++ apps/openmw/mwworld/player.hpp | 4 ++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1d55ff84dd..c23efe5792 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -538,11 +538,11 @@ namespace MWInput { resetIdleTime(); - float x = arg.state.X.rel * mCameraSensitivity * 0.2; - float y = arg.state.Y.rel * mCameraSensitivity * 0.2 * (mInvertY ? -1 : 1) * mUIYMultiplier; + float x = arg.state.X.rel * mCameraSensitivity * 0.2f; + float y = arg.state.Y.rel * mCameraSensitivity * 0.2f * (mInvertY ? -1 : 1) * mUIYMultiplier; - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); + mPlayer.setYaw(x); + mPlayer.setPitch(-y); if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b01b929c46..ea8a02dee9 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -84,6 +84,22 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Sneak, sneak); } + void Player::setYaw(float yaw) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[2] = yaw; + } + void Player::setPitch(float pitch) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[0] = pitch; + } + void Player::setRoll(float roll) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[1] = roll; + } + MWMechanics::DrawState_ Player::getDrawState() { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d82d3fc329..c985510917 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -67,6 +67,10 @@ namespace MWWorld void setRunState(bool run); void setSneak(bool sneak); + + void setYaw(float yaw); + void setPitch(float pitch); + void setRoll(float roll); }; } #endif From 4836ba16f763ceca71cbc7557ebea44561d85184 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 03:50:20 -0700 Subject: [PATCH 0833/1483] Implement turning states --- apps/openmw/mwmechanics/character.cpp | 10 ++++++++++ apps/openmw/mwmechanics/character.hpp | 3 +++ 2 files changed, 13 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 56de21d274..7aff2e1d0c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -75,6 +75,9 @@ static const struct { { CharState_SneakLeft, "sneakleft" }, { CharState_SneakRight, "sneakright" }, + { CharState_TurnLeft, "turnleft" }, + { CharState_TurnRight, "turnright" }, + { CharState_Jump, "jump" }, { CharState_Death1, "death1" }, @@ -231,6 +234,13 @@ void CharacterController::update(float duration, Movement &movement) // Apply any sideways movement manually movement.mPosition[0] += vec.x * (speed*duration); } + else if(rot.z != 0.0f && !inwater && !sneak) + { + if(rot.z > 0.0f) + setState(CharState_TurnRight, true); + else if(rot.z < 0.0f) + setState(CharState_TurnLeft, true); + } else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 61efd0be0e..5b5a65f797 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -54,6 +54,9 @@ enum CharacterState { CharState_SneakLeft, CharState_SneakRight, + CharState_TurnLeft, + CharState_TurnRight, + CharState_Jump, /* Death states must be last! */ From b0199c703ce0f37fbb2ea0b4a65d9cd77e7a8c38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 13:13:46 +0200 Subject: [PATCH 0834/1483] Companion UI --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/dialoguemanager.hpp | 2 ++ apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 28 ++++++++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 ++ apps/openmw/mwgui/container.cpp | 3 ++ apps/openmw/mwgui/container.hpp | 4 +++ apps/openmw/mwgui/dialogue.cpp | 19 +++++++++++-- apps/openmw/mwgui/hud.cpp | 3 +- apps/openmw/mwgui/inventorywindow.cpp | 5 +--- apps/openmw/mwgui/inventorywindow.hpp | 4 +-- apps/openmw/mwgui/mode.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 14 ++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 ++ apps/openmw/mwmechanics/npcstats.cpp | 22 +++++++++++++-- apps/openmw/mwmechanics/npcstats.hpp | 5 ++++ apps/openmw/mwscript/locals.cpp | 24 ++++++++++++++++ apps/openmw/mwscript/locals.hpp | 1 + apps/openmw/mwscript/scriptmanagerimp.cpp | 2 +- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_container_window.layout | 2 +- files/mygui/openmw_inventory_window.layout | 3 +- files/mygui/openmw_text.skin.xml | 5 ++++ 23 files changed, 130 insertions(+), 27 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 41f56f9931..da8d474396 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair repair soulgemdialog + merchantrepair repair soulgemdialog companionwindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index db86385d4e..de39b212ad 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -25,6 +25,8 @@ namespace MWBase virtual ~DialogueManager() {} + virtual bool isInChoice() const = 0; + virtual void startDialogue (const MWWorld::Ptr& actor) = 0; virtual void addTopic (const std::string& topic) = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 58897dc740..4d66a77423 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -201,6 +201,7 @@ namespace MWBase ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector()) = 0; + virtual void enterPressed () = 0; virtual int readPressedButton() = 0; ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) @@ -235,6 +236,7 @@ namespace MWBase virtual bool getPlayerSleeping() = 0; virtual void wakeUpPlayer() = 0; + virtual void showCompanionWindow(MWWorld::Ptr actor) = 0; virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index b75c514a29..9380ab76cd 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -117,6 +117,8 @@ namespace MWDialogue void DialogueManager::startDialogue (const MWWorld::Ptr& actor) { + mLastTopic = ""; + mChoice = -1; mIsInChoice = false; @@ -127,6 +129,9 @@ namespace MWDialogue mActorKnownTopics.clear(); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); + //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI updateTopics(); @@ -145,8 +150,6 @@ namespace MWDialogue { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); creatureStats.talkedToPlayer(); @@ -160,7 +163,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); - mLastTopic = it->mId; + mLastTopic = Misc::StringUtils::lowerCase(it->mId); mLastDialogue = *info; break; } @@ -398,6 +401,11 @@ namespace MWDialogue updateTopics(); } + bool DialogueManager::isInChoice() const + { + return mIsInChoice; + } + void DialogueManager::goodbyeSelected() { // Do not close the dialogue window if the player has to answer a question @@ -424,15 +432,13 @@ namespace MWDialogue if (mDialogueMap.find(mLastTopic) != mDialogueMap.end()) { - if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic) - { - Filter filter (mActor, mChoice, mTalkedTo); + Filter filter (mActor, mChoice, mTalkedTo); + if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic + || mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting) + { if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true)) { - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; std::string text = info->mResponse; parseText (text); @@ -440,10 +446,12 @@ namespace MWDialogue MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); executeScript (info->mResultScript); - mLastTopic = mLastTopic; mLastDialogue = *info; } } + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; } updateTopics(); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 337cf62478..a7bec31a6a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -54,6 +54,8 @@ namespace MWDialogue DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage); + virtual bool isInChoice() const; + virtual void startDialogue (const MWWorld::Ptr& actor); virtual void addTopic (const std::string& topic); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 98d818638a..8377669535 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -340,6 +340,9 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) drawItems(); mDragAndDrop->mDraggedFrom->drawItems(); + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); + notifyItemDragged(object, mDragAndDrop->mDraggedCount); + MWBase::Environment::get().getWindowManager()->setDragDrop(false); std::string sound = MWWorld::Class::get(object).getDownSoundId(object); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 49e60aa251..03bd519f7d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -82,6 +82,10 @@ namespace MWGui void setFilter(int filter); ///< set category filter void drawItems(); + /// fired when an item was moved by drag&drop. \n + /// if it was removed from this container, count will be negative. + virtual void notifyItemDragged(MWWorld::Ptr item, int count) {} + protected: bool mDisplayEquippedItems; bool mHighlightEquippedItems; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 6875b20216..b3aa27617c 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -228,7 +228,8 @@ void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) void DialogueWindow::onSelectTopic(const std::string& topic, int id) { - if (!mEnabled) return; + if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + return; int separatorPos = 0; for (unsigned int i=0; igetItemCount(); ++i) @@ -248,6 +249,11 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) { mPersuasionDialog.setVisible(true); } + else if (topic == gmst.find("sCompanionShare")->getString()) + { + mWindowManager.pushGuiMode(GM_Companion); + mWindowManager.showCompanionWindow(mPtr); + } else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) @@ -306,7 +312,10 @@ void DialogueWindow::setKeywords(std::list keyWords) { mTopicsList->clear(); - bool anyService = mServices > 0; + bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty() + && mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion"); + + bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -335,9 +344,13 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_Repair) mTopicsList->addItem(gmst.find("sRepair")->getString()); - if (anyService || mPtr.getTypeName() == typeid(ESM::NPC).name()) + if (isCompanion) + mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); + + if (anyService) mTopicsList->addSeparator(); + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) { mTopicsList->addItem(*it); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0a31a428b8..84526a28dd 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -234,7 +234,8 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) mDragAndDrop->mDraggedWidget = 0; MWBase::Environment::get().getWindowManager()->setDragDrop(false); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + mDragAndDrop->mDraggedFrom->drawItems(); + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); } else { diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 578ec3da3e..1943ff773a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -43,7 +43,6 @@ namespace MWGui getWidget(mAvatar, "Avatar"); getWidget(mAvatarImage, "AvatarImage"); getWidget(mEncumbranceBar, "EncumbranceBar"); - getWidget(mEncumbranceText, "EncumbranceBarT"); getWidget(mFilterAll, "AllButton"); getWidget(mFilterWeapon, "WeaponButton"); getWidget(mFilterApparel, "ApparelButton"); @@ -240,9 +239,7 @@ namespace MWGui float capacity = MWWorld::Class::get(player).getCapacity(player); float encumbrance = MWWorld::Class::get(player).getEncumbrance(player); - mEncumbranceBar->setProgressRange(capacity); - mEncumbranceBar->setProgressPosition(encumbrance); - mEncumbranceText->setCaption( boost::lexical_cast(int(encumbrance)) + "/" + boost::lexical_cast(int(capacity)) ); + mEncumbranceBar->setValue(encumbrance, capacity); } void InventoryWindow::onFrame() diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 7c59bab506..95657672d3 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -5,6 +5,7 @@ #include "container.hpp" #include "window_pinnable_base.hpp" +#include "widgets.hpp" namespace MWGui { @@ -36,8 +37,7 @@ namespace MWGui MyGUI::Widget* mAvatar; MyGUI::ImageBox* mAvatarImage; MyGUI::TextBox* mArmorRating; - MyGUI::ProgressBar* mEncumbranceBar; - MyGUI::TextBox* mEncumbranceText; + Widgets::MWDynamicStat* mEncumbranceBar; MyGUI::Widget* mLeftPane; MyGUI::Widget* mRightPane; diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index e9b01395f0..879fcb483f 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -9,6 +9,7 @@ namespace MWGui GM_Settings, // Settings window GM_Inventory, // Inventory mode GM_Container, + GM_Companion, GM_MainMenu, // Main menu mode GM_Console, // Console mode diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eadd657871..cf14c1f514 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -58,6 +58,7 @@ #include "merchantrepair.hpp" #include "repair.hpp" #include "soulgemdialog.hpp" +#include "companionwindow.hpp" using namespace MWGui; @@ -96,6 +97,7 @@ WindowManager::WindowManager( , mMerchantRepair(NULL) , mRepair(NULL) , mSoulgemDialog(NULL) + , mCompanionWindow(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -189,6 +191,7 @@ WindowManager::WindowManager( mMerchantRepair = new MerchantRepair(*this); mRepair = new Repair(*this); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); + mCompanionWindow = new CompanionWindow(*this, mDragAndDrop, mMessageBoxManager); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -317,6 +320,7 @@ void WindowManager::updateVisible() mTrainingWindow->setVisible(false); mMerchantRepair->setVisible(false); mRepair->setVisible(false); + mCompanionWindow->setVisible(false); mHud->setVisible(mHudEnabled); @@ -417,6 +421,10 @@ void WindowManager::updateVisible() mContainerWindow->setVisible(true); mInventoryWindow->setVisible(true); break; + case GM_Companion: + mCompanionWindow->setVisible(true); + mInventoryWindow->setVisible(true); + break; case GM_Dialogue: mDialogueWindow->setVisible(true); break; @@ -676,6 +684,7 @@ void WindowManager::onFrame (float frameDuration) mSpellCreationDialog->checkReferenceAvailable(); mEnchantingDialog->checkReferenceAvailable(); mContainerWindow->checkReferenceAvailable(); + mCompanionWindow->checkReferenceAvailable(); mConsole->checkReferenceAvailable(); } @@ -1167,6 +1176,11 @@ const Translation::Storage& WindowManager::getTranslationDataStorage() const return mTranslationDataStorage; } +void WindowManager::showCompanionWindow(MWWorld::Ptr actor) +{ + mCompanionWindow->open(actor); +} + void WindowManager::changePointer(const std::string &name) { mCursor->onCursorChange(name); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 5cf7bae02d..7a7adec27d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -77,6 +77,7 @@ namespace MWGui class MerchantRepair; class Repair; class SoulgemDialog; + class CompanionWindow; class WindowManager : public MWBase::WindowManager { @@ -229,6 +230,7 @@ namespace MWGui virtual bool getPlayerSleeping(); virtual void wakeUpPlayer(); + virtual void showCompanionWindow(MWWorld::Ptr actor); virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor); virtual void startSelfEnchanting(MWWorld::Ptr soulgem); @@ -279,6 +281,7 @@ namespace MWGui MerchantRepair* mMerchantRepair; SoulgemDialog* mSoulgemDialog; Repair* mRepair; + CompanionWindow* mCompanionWindow; Translation::Storage& mTranslationDataStorage; Cursor* mCursor; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 51e23d16ea..b9aee6abf3 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -21,8 +21,16 @@ #include "../mwbase/soundmanager.hpp" MWMechanics::NpcStats::NpcStats() -: mMovementFlags (0), mDrawState (DrawState_Nothing), mBounty (0) -, mLevelProgress(0), mDisposition(0), mVampire (0), mReputation(0), mWerewolf (false), mWerewolfKills (0) +: mMovementFlags (0) +, mDrawState (DrawState_Nothing) +, mBounty (0) +, mLevelProgress(0) +, mDisposition(0) +, mVampire (0) +, mReputation(0) +, mWerewolf (false) +, mWerewolfKills (0) +, mProfit(0) { mSkillIncreases.resize (ESM::Attribute::Length); for (int i=0; igetLocals(script); + int index = locals.getIndex(var); + char type = locals.getType(var); + if(index != -1) + { + switch(type) + { + case 's': + return mShorts.at (index); + + case 'l': + return mLongs.at (index); + + case 'f': + return mFloats.at (index); + default: + return 0; + } + } + return 0; + } bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) { diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index e933c727f3..1d9b9c3e4f 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -17,6 +17,7 @@ namespace MWScript void configure (const ESM::Script& script); bool setVarByInt(const std::string& script, const std::string& var, int val); + int getIntVar (const std::string& script, const std::string& var); ///< if var does not exist, returns 0 }; } diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index fed5877c4b..933a6e0d3b 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -114,7 +114,7 @@ namespace MWScript } catch (const std::exception& e) { - std::cerr << "exeution of script " << name << " failed." << std::endl; + std::cerr << "execution of script " << name << " failed." << std::endl; if (mVerbose) std::cerr << "(" << e.what() << ")" << std::endl; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 7da28f0bfa..af695ac6c5 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,6 +80,7 @@ set(MYGUI_FILES openmw_persuasion_dialog.layout openmw_merchantrepair.layout openmw_repair.layout + openmw_companion_window.layout smallbars.png DejaVuLGCSansMono.ttf markers.png diff --git a/files/mygui/openmw_container_window.layout b/files/mygui/openmw_container_window.layout index 452196aaea..69961e9be6 100644 --- a/files/mygui/openmw_container_window.layout +++ b/files/mygui/openmw_container_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 41bd40f923..09842f1087 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -6,8 +6,7 @@ - - + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 71e86091c8..b2a15b503b 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -158,6 +158,11 @@ + + + + + From af6409b9f57880c5f8e796b62d2fd62183ddb589 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 13:50:57 +0200 Subject: [PATCH 0835/1483] Fix NPC physics scale problem --- libs/openengine/bullet/physic.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 8de931bbf8..7b831d32c5 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -89,18 +89,19 @@ namespace Physic } void PhysicActor::setScale(float scale){ - Ogre::Vector3 position = getPosition(); - Ogre::Quaternion rotation = getRotation(); //We only need to change the scaled box translation, box rotations remain the same. mBoxScaledTranslation = mBoxScaledTranslation / mBody->getCollisionShape()->getLocalScaling().getX(); mBoxScaledTranslation *= scale; if(mBody){ mEngine->dynamicsWorld->removeRigidBody(mBody); + mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody); delete mBody; + delete mRaycastingBody; } //Create the newly scaled rigid body - mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation); - mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map + mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation()); + mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation(), 0, 0, true); + mEngine->addRigidBody(mBody, false, mRaycastingBody); //Add rigid body to dynamics world, but do not add to object map } Ogre::Vector3 PhysicActor::getHalfExtents() const From bc6e1fd9816f3acb914be559e7e79b4d84edb477 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 14:36:03 +0200 Subject: [PATCH 0836/1483] Add missing files --- apps/openmw/mwgui/companionwindow.cpp | 107 +++++++++++++++++++++ apps/openmw/mwgui/companionwindow.hpp | 39 ++++++++ files/mygui/openmw_companion_window.layout | 26 +++++ 3 files changed, 172 insertions(+) create mode 100644 apps/openmw/mwgui/companionwindow.cpp create mode 100644 apps/openmw/mwgui/companionwindow.hpp create mode 100644 files/mygui/openmw_companion_window.layout diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp new file mode 100644 index 0000000000..643cdf4c65 --- /dev/null +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -0,0 +1,107 @@ +#include "companionwindow.hpp" + +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/dialoguemanager.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "messagebox.hpp" + +namespace MWGui +{ + +CompanionWindow::CompanionWindow(MWBase::WindowManager &parWindowManager, DragAndDrop *dragAndDrop, MessageBoxManager* manager) + : ContainerBase(dragAndDrop) + , WindowBase("openmw_companion_window.layout", parWindowManager) + , mMessageBoxManager(manager) +{ + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + getWidget(mCloseButton, "CloseButton"); + getWidget(mProfitLabel, "ProfitLabel"); + getWidget(mEncumbranceBar, "EncumbranceBar"); + + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CompanionWindow::onCloseButtonClicked); + + setCoord(200,0,600,300); +} + +void CompanionWindow::open(MWWorld::Ptr npc) +{ + openContainer(npc); + setTitle(MWWorld::Class::get(npc).getName(npc)); + drawItems(); + updateEncumbranceBar(); +} + +void CompanionWindow::notifyItemDragged(MWWorld::Ptr item, int count) +{ + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + MWMechanics::NpcStats& stats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); + stats.modifyProfit(MWWorld::Class::get(item).getValue(item) * count); + } + updateEncumbranceBar(); +} + +void CompanionWindow::updateEncumbranceBar() +{ + float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr); + float encumbrance = MWWorld::Class::get(mPtr).getEncumbrance(mPtr); + mEncumbranceBar->setValue(encumbrance, capacity); + + if (mPtr.getTypeName() != typeid(ESM::NPC).name()) + mProfitLabel->setCaption(""); + else + { + MWMechanics::NpcStats& stats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); + mProfitLabel->setCaptionWithReplacing("#{sProfitValue} " + boost::lexical_cast(stats.getProfit())); + } +} + +void CompanionWindow::onWindowResize(MyGUI::Window* window) +{ + drawItems(); +} + +void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender) +{ + if (mPtr.getTypeName() == typeid(ESM::NPC).name() && MWWorld::Class::get(mPtr).getNpcStats(mPtr).getProfit() < 0) + { + std::vector buttons; + buttons.push_back("#{sCompanionWarningButtonOne}"); + buttons.push_back("#{sCompanionWarningButtonTwo}"); + mMessageBoxManager->createInteractiveMessageBox("#{sCompanionWarningMessage}", buttons); + mMessageBoxManager->eventButtonPressed += MyGUI::newDelegate(this, &CompanionWindow::onMessageBoxButtonClicked); + } + else + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); +} + +void CompanionWindow::onMessageBoxButtonClicked(int button) +{ + if (button == 0) + { + mPtr.getRefData().getLocals().setVarByInt(MWWorld::Class::get(mPtr).getScript(mPtr), + "minimumProfit", MWWorld::Class::get(mPtr).getNpcStats(mPtr).getProfit()); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); + MWBase::Environment::get().getDialogueManager()->startDialogue (mPtr); + } +} + +void CompanionWindow::onReferenceUnavailable() +{ + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); +} + + + +} diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp new file mode 100644 index 0000000000..1b64a34d50 --- /dev/null +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_MWGUI_COMPANIONWINDOW_H +#define OPENMW_MWGUI_COMPANIONWINDOW_H + +#include "container.hpp" +#include "widgets.hpp" + +namespace MWGui +{ + class MessageBoxManager; + + class CompanionWindow : public ContainerBase, public WindowBase + { + public: + CompanionWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop, MessageBoxManager* manager); + virtual ~CompanionWindow() {} + + void open(MWWorld::Ptr npc); + + virtual void notifyItemDragged(MWWorld::Ptr item, int count); + + protected: + MyGUI::Button* mCloseButton; + MyGUI::TextBox* mProfitLabel; + Widgets::MWDynamicStat* mEncumbranceBar; + MessageBoxManager* mMessageBoxManager; + + void onMessageBoxButtonClicked(int button); + + void updateEncumbranceBar(); + + void onWindowResize(MyGUI::Window* window); + void onCloseButtonClicked(MyGUI::Widget* _sender); + + virtual void onReferenceUnavailable(); + }; + +} + +#endif diff --git a/files/mygui/openmw_companion_window.layout b/files/mygui/openmw_companion_window.layout new file mode 100644 index 0000000000..6172dd5b10 --- /dev/null +++ b/files/mygui/openmw_companion_window.layout @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + From fd0aa1a4b82c4b94bc99657c1c64272e20b95c05 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 31 Mar 2013 14:46:46 +0200 Subject: [PATCH 0837/1483] Issue #685: Treat : as a whitespace --- components/compiler/scanner.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 7f43c36a55..420fd8f7f3 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -106,6 +106,12 @@ namespace Compiler mLoc.mLiteral.clear(); return true; } + else if (c==':') + { + // treat : as a whitespace :( + mLoc.mLiteral.clear(); + return true; + } else if (std::isdigit (c)) { bool cont = false; From 857f2b33dbdb14d5a0778929a0de7d12575ffa13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 14:48:48 +0200 Subject: [PATCH 0838/1483] Fix companion layout align --- files/mygui/openmw_companion_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_companion_window.layout b/files/mygui/openmw_companion_window.layout index 6172dd5b10..41a97a1ae5 100644 --- a/files/mygui/openmw_companion_window.layout +++ b/files/mygui/openmw_companion_window.layout @@ -11,7 +11,7 @@ - + From 8fd961bbac29bddb7bc838c7ed29e4268ed340c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 15:50:48 +0200 Subject: [PATCH 0839/1483] Fix ReferenceInterface not resetting the Ptr after it was deleted, causing onReferenceUnavailable to be called every frame. Fix inputmanager hiding the cursor when it shouldn't. --- apps/openmw/mwgui/referenceinterface.cpp | 3 +++ apps/openmw/mwinput/inputmanagerimp.cpp | 25 +++++------------------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index b1f7affb6f..66e036d929 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -26,7 +26,10 @@ namespace MWGui // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) || mPtr.getRefData().getCount() == 0) + { + mPtr = MWWorld::Ptr(); onReferenceUnavailable(); + } mCurrentPlayerCell = playerCell; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 33ab9b1b40..e514638bb4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -372,26 +372,11 @@ namespace MWInput void InputManager::changeInputMode(bool guiMode) { MWBase::Environment::get().getWindowManager()->setMouseVisible(guiMode); - if(guiMode) - { - // Disable mouse look - mMouseLookEnabled = false; - - mWindows.showCrosshair (false); - - // Enable GUI events - mGuiCursorEnabled = true; - } - else - { - // Enable mouse look - mMouseLookEnabled = true; - - mWindows.showCrosshair (false); - - // Disable GUI events - mGuiCursorEnabled = false; - } + mGuiCursorEnabled = guiMode; + mMouseLookEnabled = !guiMode; + if (guiMode) + mWindows.showCrosshair(false); + // if not in gui mode, the camera decides whether to show crosshair or not. } void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed) From acae815cd23edd087e7e848cb92b7d51e178a571 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sun, 31 Mar 2013 18:00:46 +0200 Subject: [PATCH 0840/1483] Added workaround for OpenCS compilation problems due to bug in Qt MOC compiler. For details please see: https://forum.openmw.org/viewtopic.php?f=7&t=1451 https://bugreports.qt-project.org/browse/QTBUG-22829 Signed-off-by: Lukasz Gromanowski --- apps/opencs/editor.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index c242a17ea8..cbdbad36f8 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -2,9 +2,9 @@ #define CS_EDITOR_H #include - +#ifndef Q_MOC_RUN #include - +#endif #include "model/doc/documentmanager.hpp" #include "view/doc/viewmanager.hpp" From 63424ade56fd9c7da96446d666e4c4e774f1c4c0 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 31 Mar 2013 17:30:03 +0000 Subject: [PATCH 0841/1483] refactoring --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 177 ++------------------- apps/openmw/mwmechanics/aitravel.hpp | 8 +- apps/openmw/mwmechanics/pathfinding.cpp | 201 ++++++++++++++++++++++++ apps/openmw/mwmechanics/pathfinding.hpp | 26 +++ 5 files changed, 245 insertions(+), 169 deletions(-) create mode 100644 apps/openmw/mwmechanics/pathfinding.cpp create mode 100644 apps/openmw/mwmechanics/pathfinding.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 41599b35db..d29e0ff2e7 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -65,7 +65,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate repair + aiescort aiactivate repair pathfinding ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 2c5260a625..df6a38bb03 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -14,7 +14,7 @@ #include "boost/tuple/tuple.hpp" MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z),isPathConstructed(false) + : mX(x),mY(y),mZ(z),mPathFinder() { } @@ -23,151 +23,17 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } -float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) -{ - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); -} - -float distance(ESM::Pathgrid::Point point,float x,float y,float z) -{ - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); -} - -float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) -{ - return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); -} - -int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) -{ - if(!grid) return -1; - if(grid->mPoints.empty()) return -1; - - float m = distance(grid->mPoints[0],x,y,z); - int i0 = 0; - - for(unsigned int i=1; imPoints.size();++i) - { - if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); - i0 = i; - } - } - return i0; -} - float sgn(float a) { if(a>0) return 1.; else return -1.; } -float getZAngle(float dX,float dY) -{ - float h = sqrt(dX*dX+dY*dY); - return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); -} - -typedef boost::adjacency_list,boost::property > PathGridGraph; -typedef boost::property_map::type WeightMap; -typedef PathGridGraph::vertex_descriptor PointID; -typedef PathGridGraph::edge_descriptor PointConnectionID; - -struct found_path {}; - -class goalVisited : public boost::default_astar_visitor -{ -public: - goalVisited(PointID goal) : mGoal(goal) {} - - void examine_vertex(PointID u, const PathGridGraph g) - { - if(u == mGoal) - throw found_path(); - } -private: - PointID mGoal; -}; - -class DistanceHeuristic : public boost::astar_heuristic -{ -public: - DistanceHeuristic(const PathGridGraph & l, PointID goal) - : mGraph(l), mGoal(goal) {} - - float operator()(PointID u) - { - const ESM::Pathgrid::Point & U = mGraph[u]; - const ESM::Pathgrid::Point & V = mGraph[mGoal]; - float dx = U.mX - V.mX; - float dy = U.mY - V.mY; - float dz = U.mZ - V.mZ; - return sqrt(dx * dx + dy * dy + dz * dz); - } -private: - const PathGridGraph & mGraph; - PointID mGoal; -}; - -std::list getPath(PointID start,PointID end,PathGridGraph graph){ - std::vector p(boost::num_vertices(graph)); - std::vector d(boost::num_vertices(graph)); - std::list shortest_path; - - try { - boost::astar_search - ( - graph, - start, - DistanceHeuristic(graph,end), - boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); - - } catch(found_path fg) { - for(PointID v = end;; v = p[v]) { - shortest_path.push_front(graph[v]); - if(p[v] == v) - break; - } - } - return shortest_path; -} - -PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) -{ - PathGridGraph graph; - - for(unsigned int i = 0;imPoints.size();++i) - { - PointID pID = boost::add_vertex(graph); - graph[pID].mX = pathgrid->mPoints[i].mX + xCell; - graph[pID].mY = pathgrid->mPoints[i].mY + yCell; - graph[pID].mZ = pathgrid->mPoints[i].mZ; - } - - for(unsigned int i = 0;imEdges.size();++i) - { - PointID u = pathgrid->mEdges[i].mV0; - PointID v = pathgrid->mEdges[i].mV1; - - PointConnectionID edge; - bool done; - boost::tie(edge,done) = boost::add_edge(u,v,graph); - WeightMap weightmap = boost::get(boost::edge_weight, graph); - weightmap[edge] = distance(graph[u],graph[v]); - - } - - return graph; -} - bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; @@ -193,7 +59,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } } - if(!isPathConstructed ||cellChange) + if(!mPathFinder.mIsPathConstructed ||cellChange) { cellX = actor.getCell()->mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; @@ -205,43 +71,26 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; } - int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); - int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); - - if(start != -1 && end != -1) - { - PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); - mPath = getPath(start,end,graph); - } - ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; dest.mZ = mZ; - mPath.push_back(dest); - isPathConstructed = true; + + ESM::Pathgrid::Point start; + dest.mX = pos.pos[0]; + dest.mY = pos.pos[1]; + dest.mZ = pos.pos[2]; + + mPathFinder.findPath(start,dest,pathgrid,xCell,yCell); } - if(mPath.empty()) + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } - ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distanceZCorrected(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) - { - mPath.pop_front(); - if(mPath.empty()) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } - nextPoint = *mPath.begin(); - } - - float dX = nextPoint.mX - pos.pos[0]; - float dY = nextPoint.mY - pos.pos[1]; - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; return false; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index ef2359ba91..52b41850f1 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -2,8 +2,7 @@ #define GAME_MWMECHANICS_AITRAVEL_H #include "aipackage.hpp" -#include -#include +#include "pathfinding.hpp" namespace MWMechanics { @@ -26,8 +25,9 @@ namespace MWMechanics int cellX; int cellY; - bool isPathConstructed; - std::list mPath; + //bool isPathConstructed; + //std::list mPath; + PathFinder mPathFinder; }; } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp new file mode 100644 index 0000000000..9b76082b48 --- /dev/null +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -0,0 +1,201 @@ +#include "pathfinding.hpp" +#include +#include +#include "boost/tuple/tuple.hpp" +#include "OgreMath.h" + +namespace MWMechanics +{ + + //helpers functions + float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) + { + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); + } + + float distance(ESM::Pathgrid::Point point,float x,float y,float z) + { + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); + } + + float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) + { + return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); + } + + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } + + int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) + { + if(!grid) return -1; + if(grid->mPoints.empty()) return -1; + + float m = distance(grid->mPoints[0],x,y,z); + int i0 = 0; + + for(unsigned int i=1; imPoints.size();++i) + { + if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); + i0 = i; + } + } + return i0; + } + + typedef boost::adjacency_list,boost::property > PathGridGraph; + typedef boost::property_map::type WeightMap; + typedef PathGridGraph::vertex_descriptor PointID; + typedef PathGridGraph::edge_descriptor PointConnectionID; + + struct found_path {}; + + class goalVisited : public boost::default_astar_visitor + { + public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } + private: + PointID mGoal; + }; + + class DistanceHeuristic : public boost::astar_heuristic + { + public: + DistanceHeuristic(const PathGridGraph & l, PointID goal) + : mGraph(l), mGoal(goal) {} + + float operator()(PointID u) + { + const ESM::Pathgrid::Point & U = mGraph[u]; + const ESM::Pathgrid::Point & V = mGraph[mGoal]; + float dx = U.mX - V.mX; + float dy = U.mY - V.mY; + float dz = U.mZ - V.mZ; + return sqrt(dx * dx + dy * dy + dz * dz); + } + private: + const PathGridGraph & mGraph; + PointID mGoal; + }; + + PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) + { + PathGridGraph graph; + + for(unsigned int i = 0;imPoints.size();++i) + { + PointID pID = boost::add_vertex(graph); + graph[pID].mX = pathgrid->mPoints[i].mX + xCell; + graph[pID].mY = pathgrid->mPoints[i].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[i].mZ; + } + + for(unsigned int i = 0;imEdges.size();++i) + { + PointID u = pathgrid->mEdges[i].mV0; + PointID v = pathgrid->mEdges[i].mV1; + + PointConnectionID edge; + bool done; + boost::tie(edge,done) = boost::add_edge(u,v,graph); + WeightMap weightmap = boost::get(boost::edge_weight, graph); + weightmap[edge] = distance(graph[u],graph[v]); + + } + + return graph; + } + + std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::vector p(boost::num_vertices(graph)); + std::vector d(boost::num_vertices(graph)); + std::list shortest_path; + + try { + boost::astar_search + ( + graph, + start, + DistanceHeuristic(graph,end), + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) + ); + + } catch(found_path fg) { + for(PointID v = end;; v = p[v]) { + shortest_path.push_front(graph[v]); + if(p[v] == v) + break; + } + } + return shortest_path; + } + + //end of helpers functions + + PathFinder::PathFinder() + { + mIsPathConstructed = false; + } + + std::list PathFinder::findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell,float yCell) + { + int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); + int end = getClosestPoint(pathGrid,endPoint.mX - xCell,endPoint.mY - yCell,endPoint.mZ); + + if(start != -1 && end != -1) + { + PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); + mPath = getPath(start,end,graph); + } + + mPath.push_back(endPoint); + mIsPathConstructed = true; + + return mPath; + } + + float PathFinder::getZAngleToNext(float x,float y,float z) + { + if(mPath.empty()) + { + return 0;/// shouldn't happen! + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + float dX = nextPoint.mX - x; + float dY = nextPoint.mY - y; + float h = sqrt(dX*dX+dY*dY); + return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); + } + + bool PathFinder::checkIfNextPointReached(float x,float y,float z) + { + if(mPath.empty()) + { + return true; + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + if(distanceZCorrected(nextPoint,x,y,z) < 20) + { + mPath.pop_front(); + if(mPath.empty()) + { + return true; + } + nextPoint = *mPath.begin(); + } + return false; + } +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp new file mode 100644 index 0000000000..200b191259 --- /dev/null +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_MWMECHANICS_PATHFINDING_H +#define GAME_MWMECHANICS_PATHFINDING_H + +#include +#include + +namespace MWMechanics +{ + class PathFinder + { + public: + PathFinder(); + + std::list findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); + + bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. + float getZAngleToNext(float x,float y,float z); + + + std::list mPath; + bool mIsPathConstructed; + }; +} + +#endif \ No newline at end of file From d29a42dcbe37b968827b7648eab6ce8f345bbf66 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 31 Mar 2013 23:18:23 +0200 Subject: [PATCH 0842/1483] Fixed enchanting mechanics --- apps/openmw/mwclass/armor.cpp | 4 ++-- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 4 ++-- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 4 ++-- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 ++-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 12 +++++++++--- apps/openmw/mwmechanics/enchanting.cpp | 21 +++++++++++---------- apps/openmw/mwmechanics/enchanting.hpp | 4 +++- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 13 files changed, 37 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 281dd1f42c..b94c270d56 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -274,7 +274,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -285,7 +285,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 0c32015a35..65f49abb7d 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 644561e52b..85b006160b 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -147,7 +147,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -159,7 +159,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index c17d4255b1..29e3de0361 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 8f29a2084d..d65376898e 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -221,7 +221,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -232,7 +232,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 4457e79fb6..c3ef22f113 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 894b38acc9..ed2a095e37 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -367,7 +367,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -378,7 +378,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 533f32f592..4774bb50be 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 7d5d1411f9..0f3b8b7cb0 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -86,10 +86,16 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(actor); - mPtr = actor; + /*Now there's no need to use other enchanters, player is the enchanter here, + even if the enchanted object is created by NPC. Could be changed later, probably + with some price formulas */ + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(player); + + mPtr = player; startEditing (); } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 3590ae0f3f..ba4e46de79 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -20,6 +20,7 @@ namespace MWMechanics { mObjectType = mOldItemPtr.getTypeName(); mOldItemId = mOldItemPtr.getCellRef().mRefID; + mOldItemCount = mOldItemPtr.getRefData().getCount(); } else { @@ -50,7 +51,8 @@ namespace MWMechanics int Enchanting::create() { - mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + mEnchantment.mData.mCharge = getGemCharge(); + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { @@ -60,9 +62,6 @@ namespace MWMechanics MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } - mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); - - mEnchantment.mData.mCharge = getGemCharge(); if(mEnchantType==3) { mEnchantment.mData.mCharge=0; @@ -70,15 +69,17 @@ namespace MWMechanics mEnchantment.mData.mType = mEnchantType; mEnchantment.mData.mCost = getEnchantCost(); mEnchantment.mEffects = mEffectList; + const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); - std::string newobjId = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + + mOldItemPtr.getRefData().setCount(1); + + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); + ref.getPtr().getRefData().setCount (mOldItemCount-1); + MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobjId); - MWWorld::Ptr newobjPtr = ref.getPtr(); - MWWorld::Ptr result = mOldItemPtr; - result.mPtr = newobjPtr.mPtr; - MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (result); return 1; } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index fffa2c5b20..1a7dde708c 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -13,7 +13,7 @@ namespace MWMechanics MWWorld::Ptr mOldItemPtr; MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mEnchanter; - const MWWorld::Ptr *mNewItemPtr; + int mEnchantType; bool mSelfEnchanting; @@ -24,6 +24,8 @@ namespace MWMechanics std::string mNewItemName; std::string mObjectType; std::string mOldItemId; + int mOldItemCount; + public: Enchanting(); void setEnchanter(MWWorld::Ptr enchanter); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 876328641a..9a83063c03 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -246,7 +246,7 @@ namespace MWWorld return ""; } - std::string Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 012a03bf62..2f010eb3d7 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -234,7 +234,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; From 10d04c928c894d512e999b52e8cea77e8c01eea7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 15:12:10 -0700 Subject: [PATCH 0843/1483] Use the object's class to check if it's an actor --- .../mwmechanics/mechanicsmanagerimp.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 32fa58980d..0af7a46655 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -178,10 +178,10 @@ namespace MWMechanics void MechanicsManager::add(const MWWorld::Ptr& ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.addActivator(ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.addActor(ptr); + else + mActivators.addActivator(ptr); } void MechanicsManager::remove(const MWWorld::Ptr& ptr) @@ -194,10 +194,10 @@ namespace MWMechanics void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.updateActivator(old, ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.updateActor(old, ptr); + else + mActivators.updateActivator(old, ptr); } @@ -656,17 +656,17 @@ namespace MWMechanics void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.playAnimationGroup(ptr, groupName, mode, number); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); + else + mActivators.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.skipAnimation(ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.skipAnimation(ptr); + else + mActivators.skipAnimation(ptr); } } From 04aeb3dd07f53f4cb3484287f5a73399de78ad63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 15:29:41 -0700 Subject: [PATCH 0844/1483] Rename Mechanics' Activators to Objects --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/activators.cpp | 81 ------------------- apps/openmw/mwmechanics/activators.hpp | 45 ----------- .../mwmechanics/mechanicsmanagerimp.cpp | 14 ++-- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +- apps/openmw/mwmechanics/objects.cpp | 81 +++++++++++++++++++ apps/openmw/mwmechanics/objects.hpp | 45 +++++++++++ 7 files changed, 136 insertions(+), 136 deletions(-) delete mode 100644 apps/openmw/mwmechanics/activators.cpp delete mode 100644 apps/openmw/mwmechanics/activators.hpp create mode 100644 apps/openmw/mwmechanics/objects.cpp create mode 100644 apps/openmw/mwmechanics/objects.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index da8d474396..beb0b9aadf 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -63,7 +63,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators + mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate repair enchanting ) diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp deleted file mode 100644 index cbc3802995..0000000000 --- a/apps/openmw/mwmechanics/activators.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "activators.hpp" - -#include - -#include "movement.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -namespace MWMechanics -{ - -Activators::Activators() -{ -} - -void Activators::addActivator(const MWWorld::Ptr& ptr) -{ - MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if(anim != NULL) - mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); -} - -void Activators::removeActivator (const MWWorld::Ptr& ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - mActivators.erase(iter); -} - -void Activators::updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(old); - if(iter != mActivators.end()) - { - CharacterController ctrl = iter->second; - mActivators.erase(iter); - - ctrl.updatePtr(ptr); - mActivators.insert(std::make_pair(ptr, ctrl)); - } -} - -void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) -{ - PtrControllerMap::iterator iter = mActivators.begin(); - while(iter != mActivators.end()) - { - if(iter->first.getCell()==cellStore) - mActivators.erase(iter++); - else - ++iter; - } -} - -void Activators::update(float duration, bool paused) -{ - if(!paused) - { - for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) - { - Movement movement; - iter->second.update(duration, movement); - } - } -} - -void Activators::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - iter->second.playGroup(groupName, mode, number); -} -void Activators::skipAnimation(const MWWorld::Ptr& ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - iter->second.skipAnim(); -} - -} diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp deleted file mode 100644 index 137674a57a..0000000000 --- a/apps/openmw/mwmechanics/activators.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATRS_H - -#include -#include - -#include "character.hpp" - -namespace MWWorld -{ - class Ptr; - class CellStore; -} - -namespace MWMechanics -{ - class Activators - { - typedef std::map PtrControllerMap; - PtrControllerMap mActivators; - - public: - Activators(); - - void addActivator (const MWWorld::Ptr& ptr); - ///< Register an animated activator - - void removeActivator (const MWWorld::Ptr& ptr); - ///< Deregister an activator - - void updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); - ///< Updates an activator with a new Ptr - - void dropActivators (const MWWorld::CellStore *cellStore); - ///< Deregister all activators in the given cell. - - void update (float duration, bool paused); - ///< Update activator animations - - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); - void skipAnimation(const MWWorld::Ptr& ptr); - }; -} - -#endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0af7a46655..c8d8279210 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -181,7 +181,7 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.addActor(ptr); else - mActivators.addActivator(ptr); + mObjects.addObject(ptr); } void MechanicsManager::remove(const MWWorld::Ptr& ptr) @@ -189,7 +189,7 @@ namespace MWMechanics if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); - mActivators.removeActivator(ptr); + mObjects.removeObject(ptr); } void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) @@ -197,7 +197,7 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.updateActor(old, ptr); else - mActivators.updateActivator(old, ptr); + mObjects.updateObject(old, ptr); } @@ -207,7 +207,7 @@ namespace MWMechanics mWatched = MWWorld::Ptr(); mActors.dropActors(cellStore); - mActivators.dropActivators(cellStore); + mObjects.dropObjects(cellStore); } @@ -319,7 +319,7 @@ namespace MWMechanics } mActors.update(duration, paused); - mActivators.update(duration, paused); + mObjects.update(duration, paused); } void MechanicsManager::restoreDynamicStats() @@ -659,14 +659,14 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); else - mActivators.playAnimationGroup(ptr, groupName, mode, number); + mObjects.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { if(MWWorld::Class::get(ptr).isActor()) mActors.skipAnimation(ptr); else - mActivators.skipAnimation(ptr); + mObjects.skipAnimation(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5ad8705719..4b8d42cd30 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,7 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" -#include "activators.hpp" +#include "objects.hpp" #include "actors.hpp" namespace Ogre @@ -31,7 +31,7 @@ namespace MWMechanics bool mClassSelected; bool mRaceSelected; - Activators mActivators; + Objects mObjects; Actors mActors; void buildPlayer(); diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp new file mode 100644 index 0000000000..22b996a839 --- /dev/null +++ b/apps/openmw/mwmechanics/objects.cpp @@ -0,0 +1,81 @@ +#include "objects.hpp" + +#include + +#include "movement.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +Objects::Objects() +{ +} + +void Objects::addObject(const MWWorld::Ptr& ptr) +{ + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); + if(anim != NULL) + mObjects.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); +} + +void Objects::removeObject(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + mObjects.erase(iter); +} + +void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(old); + if(iter != mObjects.end()) + { + CharacterController ctrl = iter->second; + mObjects.erase(iter); + + ctrl.updatePtr(ptr); + mObjects.insert(std::make_pair(ptr, ctrl)); + } +} + +void Objects::dropObjects (const MWWorld::Ptr::CellStore *cellStore) +{ + PtrControllerMap::iterator iter = mObjects.begin(); + while(iter != mObjects.end()) + { + if(iter->first.getCell()==cellStore) + mObjects.erase(iter++); + else + ++iter; + } +} + +void Objects::update(float duration, bool paused) +{ + if(!paused) + { + for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter) + { + Movement movement; + iter->second.update(duration, movement); + } + } +} + +void Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + iter->second.playGroup(groupName, mode, number); +} +void Objects::skipAnimation(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + iter->second.skipAnim(); +} + +} diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp new file mode 100644 index 0000000000..6f111985c8 --- /dev/null +++ b/apps/openmw/mwmechanics/objects.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_MWMECHANICS_ACTIVATORS_H +#define GAME_MWMECHANICS_ACTOVATRS_H + +#include +#include + +#include "character.hpp" + +namespace MWWorld +{ + class Ptr; + class CellStore; +} + +namespace MWMechanics +{ + class Objects + { + typedef std::map PtrControllerMap; + PtrControllerMap mObjects; + + public: + Objects(); + + void addObject (const MWWorld::Ptr& ptr); + ///< Register an animated object + + void removeObject (const MWWorld::Ptr& ptr); + ///< Deregister an object + + void updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an object with a new Ptr + + void dropObjects(const MWWorld::CellStore *cellStore); + ///< Deregister all objects in the given cell. + + void update(float duration, bool paused); + ///< Update object animations + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); + }; +} + +#endif From d0703efd69ac5d7e0e8874d19005d2acdf2d9772 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 16:12:02 -0700 Subject: [PATCH 0845/1483] Another place to check the class' isActor method --- apps/openmw/mwmechanics/character.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7aff2e1d0c..02a5aa1006 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -111,17 +111,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); getStateInfo(mState, &mCurrentGroup); - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - { - /* Don't accumulate with activators (they don't get moved). */ - mAnimation->setAccumulation(Ogre::Vector3::ZERO); - } - else + if(MWWorld::Class::get(mPtr).isActor()) { /* Accumulate along X/Y only for now, until we can figure out how we should * handle knockout and death which moves the character down. */ mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); } + else + { + /* Don't accumulate with non-actors. */ + mAnimation->setAccumulation(Ogre::Vector3(0.0f)); + } if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", "stop", loop); } From f976eb5bd8f3a083f54adde1dab4726a923a9ad5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 17:31:52 -0700 Subject: [PATCH 0846/1483] Improve mouselook scaling --- apps/openmw/mwinput/inputmanagerimp.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e514638bb4..74d581b811 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -521,11 +521,13 @@ namespace MWInput { resetIdleTime(); - float x = arg.state.X.rel * mCameraSensitivity * 0.2f; - float y = arg.state.Y.rel * mCameraSensitivity * 0.2f * (mInvertY ? -1 : 1) * mUIYMultiplier; + float x = arg.state.X.rel * (1.0f/256.0f) * mCameraSensitivity; + float y = arg.state.Y.rel * (1.0f/256.0f) * mCameraSensitivity * mCameraYMultiplier * (mInvertY ? -1 : 1); + float scale = MWBase::Environment::get().getFrameDuration(); + if(scale <= 0.0f) scale = 1.0f; - mPlayer.setYaw(x); - mPlayer.setPitch(-y); + mPlayer.setYaw(x/scale); + mPlayer.setPitch(-y/scale); if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); From 26db983599daee021e2608cf37eba34254f75892 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 1 Apr 2013 10:46:08 +0200 Subject: [PATCH 0847/1483] minor fix --- apps/openmw/mwmechanics/objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 6f111985c8..3a2e51644e 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -1,5 +1,5 @@ #ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATRS_H +#define GAME_MWMECHANICS_ACTOVATORS_H #include #include From 47cc945ef47e646e29a2f49d997ec8b0ba274fd4 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 12:38:13 +0000 Subject: [PATCH 0848/1483] more refactoring --- apps/openmw/mwmechanics/aitravel.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 17 ++++++++++++----- apps/openmw/mwmechanics/pathfinding.hpp | 5 ++++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index df6a38bb03..b1a4cd0a69 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -59,7 +59,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } } - if(!mPathFinder.mIsPathConstructed ||cellChange) + if(!mPathFinder.isPathConstructed() ||cellChange) { cellX = actor.getCell()->mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; @@ -81,7 +81,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) dest.mY = pos.pos[1]; dest.mZ = pos.pos[2]; - mPathFinder.findPath(start,dest,pathgrid,xCell,yCell); + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9b76082b48..fdac50ddac 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -118,7 +118,7 @@ namespace MWMechanics return graph; } - std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::list findPath(PointID start,PointID end,PathGridGraph graph){ std::vector p(boost::num_vertices(graph)); std::vector d(boost::num_vertices(graph)); std::list shortest_path; @@ -149,7 +149,7 @@ namespace MWMechanics mIsPathConstructed = false; } - std::list PathFinder::findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell,float yCell) { int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); @@ -158,13 +158,11 @@ namespace MWMechanics if(start != -1 && end != -1) { PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); - mPath = getPath(start,end,graph); + mPath = findPath(start,end,graph); } mPath.push_back(endPoint); mIsPathConstructed = true; - - return mPath; } float PathFinder::getZAngleToNext(float x,float y,float z) @@ -198,4 +196,13 @@ namespace MWMechanics } return false; } + + std::list PathFinder::getPath() + { + return mPath; + } + bool PathFinder::isPathConstructed() + { + return mIsPathConstructed; + } } \ No newline at end of file diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 200b191259..b1bbab37ab 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -11,13 +11,16 @@ namespace MWMechanics public: PathFinder(); - std::list findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. float getZAngleToNext(float x,float y,float z); + std::list getPath(); + bool isPathConstructed(); + private: std::list mPath; bool mIsPathConstructed; }; From 1bff6ed872f9deb860682fae7e398c8778433292 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 1 Apr 2013 17:12:47 +0200 Subject: [PATCH 0849/1483] Enchaning values import, fixed constness --- apps/openmw/mwmechanics/enchanting.cpp | 46 ++++++++++++++------------ apps/openmw/mwmechanics/enchanting.hpp | 22 ++++++------ 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index ba4e46de79..d86f7c1511 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -29,7 +29,7 @@ namespace MWMechanics } } - void Enchanting::setNewItemName(std::string s) + void Enchanting::setNewItemName(const std::string& s) { mNewItemName=s; } @@ -39,7 +39,7 @@ namespace MWMechanics mEffectList=effectList; } - int Enchanting::getEnchantType() + int Enchanting::getEnchantType() const { return mEnchantType; } @@ -49,30 +49,31 @@ namespace MWMechanics mSoulGemPtr=soulGem; } - int Enchanting::create() + bool Enchanting::create() { - mEnchantment.mData.mCharge = getGemCharge(); + ESM::Enchantment enchantment; + enchantment.mData.mCharge = getGemCharge(); mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { if(getEnchantChance() (RAND_MAX)*100) - return 0; + return false; MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } if(mEnchantType==3) { - mEnchantment.mData.mCharge=0; + enchantment.mData.mCharge=0; } - mEnchantment.mData.mType = mEnchantType; - mEnchantment.mData.mCost = getEnchantCost(); - mEnchantment.mEffects = mEffectList; + enchantment.mData.mType = mEnchantType; + enchantment.mData.mCost = getEnchantCost(); + enchantment.mEffects = mEffectList; - const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); + const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment); - MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName); mOldItemPtr.getRefData().setCount(1); @@ -80,7 +81,7 @@ namespace MWMechanics ref.getPtr().getRefData().setCount (mOldItemCount-1); MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - return 1; + return true; } void Enchanting::nextEnchantType() @@ -93,12 +94,13 @@ namespace MWMechanics } if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) { + int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); switch(mEnchantType) { case 1: mEnchantType = 2; case 3: - if(getGemCharge()<400) + if(getGemCharge()getStore(); float cost = 0; @@ -138,7 +140,8 @@ namespace MWMechanics if(mEnchantType==3) { - cost1 *= 100; + int constDurationMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantDurationMult")->getFloat(); + cost1 *= constDurationMultipler; cost2 *= 2; } if(effect->mData.mFlags & ESM::MagicEffect::CastTarget) @@ -152,7 +155,7 @@ namespace MWMechanics } return cost; } - int Enchanting::getGemCharge() + int Enchanting::getGemCharge() const { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); if(soulEmpty()) @@ -163,20 +166,20 @@ namespace MWMechanics return soul->mData.mSoul; } - int Enchanting::getMaxEnchantValue() + int Enchanting::getMaxEnchantValue() const { if (itemEmpty()) return 0; return MWWorld::Class::get(mOldItemPtr).getEnchantmentPoints(mOldItemPtr); } - bool Enchanting::soulEmpty() + bool Enchanting::soulEmpty() const { if (mSoulGemPtr.isEmpty()) return true; return false; } - bool Enchanting::itemEmpty() + bool Enchanting::itemEmpty() const { if(mOldItemPtr.isEmpty()) return true; @@ -193,7 +196,7 @@ namespace MWMechanics mEnchanter = enchanter; } - float Enchanting::getEnchantChance() + float Enchanting::getEnchantChance() const { /* Formula from http://www.uesp.net/wiki/Morrowind:Enchant @@ -208,7 +211,8 @@ namespace MWMechanics float chance2 = 2.5 * getEnchantCost(); if(mEnchantType==3) { - chance2 *= 2; + float constantChance = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantChanceMult")->getFloat(); + chance2 /= constantChance; } return (chance1-chance2); } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 1a7dde708c..c951ae8256 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -9,7 +9,6 @@ namespace MWMechanics { class Enchanting { - MWWorld::Ptr mOldItemPtr; MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mEnchanter; @@ -19,7 +18,6 @@ namespace MWMechanics bool mSelfEnchanting; ESM::EffectList mEffectList; - ESM::Enchantment mEnchantment; std::string mNewItemName; std::string mObjectType; @@ -31,18 +29,18 @@ namespace MWMechanics void setEnchanter(MWWorld::Ptr enchanter); void setSelfEnchanting(bool selfEnchanting); void setOldItem(MWWorld::Ptr oldItem); - void setNewItemName(std::string s); + void setNewItemName(const std::string& s); void setEffect(ESM::EffectList effectList); void setSoulGem(MWWorld::Ptr soulGem); - int create(); - void nextEnchantType(); - int getEnchantType(); - int getEnchantCost(); - int getMaxEnchantValue(); - int getGemCharge(); - float getEnchantChance(); - bool soulEmpty(); - bool itemEmpty(); + bool create(); //Return true if created, false if failed. + void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) + int getEnchantType() const; + int getEnchantCost() const; + int getMaxEnchantValue() const; + int getGemCharge() const; + float getEnchantChance() const; + bool soulEmpty() const; //Return true if empty + bool itemEmpty() const; //Return true if empty }; } #endif From 9dbd024076efabe5e3a109e359495bb9f7c75cee Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 1 Apr 2013 17:30:54 +0200 Subject: [PATCH 0850/1483] another minor fix --- apps/openmw/mwmechanics/objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 3a2e51644e..7b1185a29a 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -1,5 +1,5 @@ #ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATORS_H +#define GAME_MWMECHANICS_ACTIVATORS_H #include #include From 2be9405c96056fc6a12b2c5d4d048e0d74ca3d6d Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 15:44:08 +0000 Subject: [PATCH 0851/1483] the sgn function is no longer in the global namespace --- apps/openmw/mwmechanics/aitravel.cpp | 157 ++++++++++++++------------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b1a4cd0a69..4aca5f3d49 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,92 +13,95 @@ #include #include "boost/tuple/tuple.hpp" -MWMechanics::AiTravel::AiTravel(float x, float y, float z) - : mX(x),mY(y),mZ(z),mPathFinder() +namespace MWMechanics { -} -MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const -{ - return new AiTravel(*this); -} - -float sgn(float a) -{ - if(a>0) return 1.; - else return -1.; -} - -bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) -{ - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - ESM::Position pos = actor.getRefData().getPosition(); - bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + AiTravel::AiTravel(float x, float y, float z) + : mX(x),mY(y),mZ(z),mPathFinder() { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + } + + AiTravel * AiTravel::clone() const + { + return new AiTravel(*this); + } + + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } + + bool AiTravel::execute (const MWWorld::Ptr& actor) + { + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + + if(!mPathFinder.isPathConstructed() ||cellChange) + { + cellX = actor.getCell()->mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; + float xCell = 0; + float yCell = 0; + if (actor.getCell()->mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } + + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + + ESM::Pathgrid::Point start; + dest.mX = pos.pos[0]; + dest.mY = pos.pos[1]; + dest.mZ = pos.pos[2]; + + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); + } + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } + + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + + return false; } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + + int AiTravel::getTypeId() const { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } + return 1; } - if(!mPathFinder.isPathConstructed() ||cellChange) - { - cellX = actor.getCell()->mCell->mData.mX; - cellY = actor.getCell()->mCell->mData.mY; - float xCell = 0; - float yCell = 0; - if (actor.getCell()->mCell->isExterior()) - { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; - } - - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; - - ESM::Pathgrid::Point start; - dest.mX = pos.pos[0]; - dest.mY = pos.pos[1]; - dest.mZ = pos.pos[2]; - - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); - } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } - - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; - - return false; } - -int MWMechanics::AiTravel::getTypeId() const -{ - return 1; -} - - From 20af7d89a2550a9873dd0ab03d5240af25f3b0f7 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 17:30:40 +0000 Subject: [PATCH 0852/1483] post master-merge fixes. Looks a little odd. --- apps/openmw/mwmechanics/aitravel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 4aca5f3d49..dd769f91c4 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -47,7 +47,7 @@ namespace MWMechanics //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } @@ -57,7 +57,7 @@ namespace MWMechanics //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } @@ -88,13 +88,13 @@ namespace MWMechanics } if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; return false; } From 6a33170ca244db400d49651597ce3cc80d753723 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 17:44:06 +0000 Subject: [PATCH 0853/1483] More bugfix, but I don't like this one. --- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index dd769f91c4..25efe8fff0 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -26,7 +26,7 @@ namespace MWMechanics return new AiTravel(*this); } - float sgn(float a) + static float sgn(float a) { if(a>0) return 1.; else return -1.; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index fdac50ddac..1d98674ef5 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -23,7 +23,7 @@ namespace MWMechanics return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); } - float sgn(float a) + static float sgn(float a) { if(a>0) return 1.; else return -1.; From d25c838e1d3c5f9aabfc4c41e1482e835c6c034e Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 11:42:29 +0200 Subject: [PATCH 0854/1483] Bugfix #646 --- apps/openmw/mwworld/actionequip.cpp | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index afbb505f22..513182a2dc 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -108,6 +108,46 @@ namespace MWWorld } + //Disable twohanded when shield equipped, shield when twohanded equipped + if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) + { + invStore.equip(*slot, it); + + if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + } + } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + } + } + // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) { From c71edb613d12e3b46bd4d0e998e054bbcf4cc330 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 12:00:45 +0200 Subject: [PATCH 0855/1483] added faction table --- apps/opencs/model/world/data.cpp | 16 ++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 3 +++ components/esm/loadfact.cpp | 25 +++++++++++++++++++++++-- components/esm/loadfact.hpp | 3 +++ 9 files changed, 67 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 7b3e667715..825e29a232 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -57,10 +57,15 @@ CSMWorld::Data::Data() mClasses.addColumn (new PlayableColumn); mClasses.addColumn (new DescriptionColumn); + mFactions.addColumn (new StringIdColumn); + mFactions.addColumn (new RecordStateColumn); + mFactions.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); + addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); } CSMWorld::Data::~Data() @@ -99,6 +104,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSkills() return mSkills; } +const CSMWorld::IdCollection& CSMWorld::Data::getFactions() const +{ + return mFactions; +} + +CSMWorld::IdCollection& CSMWorld::Data::getFactions() +{ + return mFactions; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -137,6 +152,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_GMST: mGmsts.load (reader, base); break; case ESM::REC_SKIL: mSkills.load (reader, base); break; case ESM::REC_CLAS: mClasses.load (reader, base); break; + case ESM::REC_FACT: mFactions.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 7baf03259e..1e2894774a 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -24,6 +25,7 @@ namespace CSMWorld IdCollection mGmsts; IdCollection mSkills; IdCollection mClasses; + IdCollection mFactions; std::vector mModels; std::map mModelIndex; @@ -52,6 +54,10 @@ namespace CSMWorld IdCollection& getSkills(); + const IdCollection& getFactions() const; + + IdCollection& getFactions(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index a85b30c2a8..985cab0d4c 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -21,6 +21,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -31,6 +32,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 4c4d95654b..0190467c4b 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -41,7 +41,9 @@ namespace CSMWorld Type_Skills, Type_Skill, Type_Classes, - Type_Class + Type_Class, + Type_Factions, + Type_Faction }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 2ef66593f7..3c4bc3b047 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -94,6 +94,10 @@ void CSVDoc::View::setupWorldMenu() connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView())); world->addAction (classes); + QAction *factions = new QAction (tr ("Factions"), this); + connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); + world->addAction (factions); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -262,6 +266,11 @@ void CSVDoc::View::addClassesSubView() addSubView (CSMWorld::UniversalId::Type_Classes); } +void CSVDoc::View::addFactionsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Factions); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index bc8e8fc26d..03905430a8 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -119,6 +119,8 @@ namespace CSVDoc void addSkillsSubView(); void addClassesSubView(); + + void addFactionsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 5d715ea21e..cbfbf6b464 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -20,6 +20,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Classes, new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Factions, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); + // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 6ea66977d5..50fb94bbb7 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -33,7 +33,7 @@ void Faction::load(ESMReader &esm) void Faction::save(ESMWriter &esm) { esm.writeHNCString("FNAM", mName); - + for (int i = 0; i < 10; i++) { if (mRanks[i].empty()) @@ -43,7 +43,7 @@ void Faction::save(ESMWriter &esm) } esm.writeHNT("FADT", mData, 240); - + for (std::vector::iterator it = mReactions.begin(); it != mReactions.end(); ++it) { esm.writeHNString("ANAM", it->mFaction); @@ -51,4 +51,25 @@ void Faction::save(ESMWriter &esm) } } + void Faction::blank() + { + mName.clear(); + mData.mAttribute1 = mData.mAttribute2 = 0; + mData.mUnknown = -1; + mData.mIsHidden = 0; + + for (int i=0; i<10; ++i) + { + mData.mRankData[i].mAttribute1 = mData.mRankData[i].mAttribute2 = 0; + mData.mRankData[i].mSkill1 = mData.mRankData[i].mSkill2 = 0; + mData.mRankData[i].mFactReaction = 0; + + mRanks[i].clear(); + } + + for (int i=0; i<6; ++i) + mData.mSkillID[i] = 0; + + mReactions.clear(); + } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 49898b1cf2..a2ba688c01 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -58,6 +58,9 @@ struct Faction void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From f9f520df34373dc585d7bf695362564a6b7fe3b7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 13:59:45 +0200 Subject: [PATCH 0856/1483] adjusted faction record to increase consistency with other records --- apps/esmtool/record.cpp | 14 +++++++------- apps/openmw/mwdialogue/filter.cpp | 4 ++-- apps/openmw/mwgui/stats_window.cpp | 6 +++--- apps/openmw/mwmechanics/npcstats.cpp | 2 +- components/esm/loadclas.cpp | 19 +++++++++++++++++++ components/esm/loadclas.hpp | 6 ++++++ components/esm/loadfact.cpp | 21 +++++++++++++++++++-- components/esm/loadfact.hpp | 10 ++++++++-- 8 files changed, 65 insertions(+), 17 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index de3a175106..8f77e4b445 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -679,14 +679,14 @@ void Record::print() std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl; if (mData.mData.mUnknown != -1) std::cout << " Unknown: " << mData.mData.mUnknown << std::endl; - std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute1) - << " (" << mData.mData.mAttribute1 << ")" << std::endl; - std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute2) - << " (" << mData.mData.mAttribute2 << ")" << std::endl; + std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttributes[0]) + << " (" << mData.mData.mAttributes[0] << ")" << std::endl; + std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttributes[1]) + << " (" << mData.mData.mAttributes[1] << ")" << std::endl; for (int i = 0; i != 6; i++) - if (mData.mData.mSkillID[i] != -1) - std::cout << " Skill: " << skillLabel(mData.mData.mSkillID[i]) - << " (" << mData.mData.mSkillID[i] << ")" << std::endl; + if (mData.mData.mSkills[i] != -1) + std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) + << " (" << mData.mData.mSkills[i] << ")" << std::endl; for (int i = 0; i != 10; i++) if (mData.mRanks[i] != "") { diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index f7e9529568..ddb15d423d 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -569,8 +569,8 @@ bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& ac MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor); - return stats.getAttribute (faction.mData.mAttribute1).getBase()>=faction.mData.mRankData[rank].mAttribute1 && - stats.getAttribute (faction.mData.mAttribute2).getBase()>=faction.mData.mRankData[rank].mAttribute2; + return stats.getAttribute (faction.mData.mAttributes[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && + stats.getAttribute (faction.mData.mAttributes[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; } bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 0fa4127b55..86019fa28d 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -500,8 +500,8 @@ void StatsWindow::updateSkillArea() text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute1); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute2); + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttributes[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttributes[1]); assert(attr1 && attr2); text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) @@ -511,7 +511,7 @@ void StatsWindow::updateSkillArea() text += "\n#BF9959"; for (int i=0; i<6; ++i) { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkillID[i]]+"}"; + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; if (i<5) text += ", "; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index b9aee6abf3..7216e8fe0e 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -334,7 +334,7 @@ bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int std::vector skills; for (int i=0; i<6; ++i) - skills.push_back (static_cast (getSkill (faction.mData.mSkillID[i]).getModified())); + skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getModified())); std::sort (skills.begin(), skills.end()); diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index d9f367fd63..bdc4614625 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -1,5 +1,7 @@ #include "loadclas.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" @@ -18,6 +20,23 @@ const char *Class::sGmstSpecializationIds[3] = { "sSpecializationStealth" }; + + int& Class::CLDTstruct::getSkill (int index, bool major) + { + if (index<0 || index>=5) + throw std::logic_error ("skill index out of range"); + + return mSkills[index][major ? 1 : 0]; + } + + int Class::CLDTstruct::getSkill (int index, bool major) const + { + if (index<0 || index>=5) + throw std::logic_error ("skill index out of range"); + + return mSkills[index][major ? 1 : 0]; + } + void Class::load(ESMReader &esm) { mName = esm.getHNString("FNAM"); diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index ac596af32c..4f85e6ee8b 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -58,6 +58,12 @@ struct Class // I have no idea how to autocalculate these items... int mCalc; + + int& getSkill (int index, bool major); + ///< Throws an exception for invalid values of \a index. + + int getSkill (int index, bool major) const; + ///< Throws an exception for invalid values of \a index. }; // 60 bytes std::string mId, mName, mDescription; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 50fb94bbb7..12a76f1ade 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -1,10 +1,27 @@ #include "loadfact.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" namespace ESM { + int& Faction::FADTstruct::getSkill (int index, bool ignored) + { + if (index<0 || index>=6) + throw std::logic_error ("skill index out of range"); + + return mSkills[index]; + } + + int Faction::FADTstruct::getSkill (int index, bool ignored) const + { + if (index<0 || index>=6) + throw std::logic_error ("skill index out of range"); + + return mSkills[index]; + } void Faction::load(ESMReader &esm) { @@ -54,7 +71,7 @@ void Faction::save(ESMWriter &esm) void Faction::blank() { mName.clear(); - mData.mAttribute1 = mData.mAttribute2 = 0; + mData.mAttributes[0] = mData.mAttributes[1] = 0; mData.mUnknown = -1; mData.mIsHidden = 0; @@ -68,7 +85,7 @@ void Faction::save(ESMWriter &esm) } for (int i=0; i<6; ++i) - mData.mSkillID[i] = 0; + mData.mSkills[i] = 0; mReactions.clear(); } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index a2ba688c01..edc4640bb1 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -34,13 +34,19 @@ struct Faction struct FADTstruct { // Which attributes we like - int mAttribute1, mAttribute2; + int mAttributes[2]; RankData mRankData[10]; - int mSkillID[6]; // IDs of skills this faction require + int mSkills[6]; // IDs of skills this faction require int mUnknown; // Always -1? int mIsHidden; // 1 - hidden from player + + int& getSkill (int index, bool ignored = false); + ///< Throws an exception for invalid values of \a index. + + int getSkill (int index, bool ignored = false) const; + ///< Throws an exception for invalid values of \a index. }; // 240 bytes FADTstruct mData; From ec6bdbeb40dd3641233ac5e22b4557ee795affe0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 14:04:13 +0200 Subject: [PATCH 0857/1483] added skill columns to faction table --- apps/opencs/model/world/columns.hpp | 8 ++++---- apps/opencs/model/world/data.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index cbcddd972d..9345df0d20 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -347,15 +347,15 @@ namespace CSMWorld int mIndex; bool mMajor; - SkillsColumn (int index, bool major) - : Column ((major ? "Major Skill #" : "Minor Skill #")+ + SkillsColumn (int index, bool typePrefix = false, bool major = false) + : Column ((typePrefix ? (major ? "Major Skill #" : "Minor Skill #") : "Skill #")+ boost::lexical_cast (index), ColumnBase::Display_String), mIndex (index), mMajor (major) {} virtual QVariant get (const Record& record) const { - int skill = record.get().mData.mSkills[mIndex][mMajor ? 1 : 0]; + int skill = record.get().mData.getSkill (mIndex, mMajor); return QString::fromUtf8 (ESM::Skill::indexToId (skill).c_str()); } @@ -373,7 +373,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - record2.mData.mSkills[mIndex][mMajor ? 1 : 0] = index; + record2.mData.getSkill (mIndex, mMajor) = index; record.setModified (record2); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 825e29a232..23a1eb91b9 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -51,15 +51,17 @@ CSMWorld::Data::Data() mClasses.addColumn (new AttributesColumn (1)); mClasses.addColumn (new SpecialisationColumn); for (int i=0; i<5; ++i) - mClasses.addColumn (new SkillsColumn (i, true)); + mClasses.addColumn (new SkillsColumn (i, true, true)); for (int i=0; i<5; ++i) - mClasses.addColumn (new SkillsColumn (i, false)); + mClasses.addColumn (new SkillsColumn (i, true, false)); mClasses.addColumn (new PlayableColumn); mClasses.addColumn (new DescriptionColumn); mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + for (int i=0; i<6; ++i) + mFactions.addColumn (new SkillsColumn (i)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 900c2cfa81b629a74fcb3ce112fbbf1578217c3a Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 14:08:59 +0200 Subject: [PATCH 0858/1483] Minor bugfix #646 change --- apps/openmw/mwworld/actionequip.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 513182a2dc..9a44a99791 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -111,8 +111,6 @@ namespace MWWorld //Disable twohanded when shield equipped, shield when twohanded equipped if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - invStore.equip(*slot, it); - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) { if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || From 384c88182dfa5ab54e215bafa99edc8cfed6a867 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 14:15:22 +0200 Subject: [PATCH 0859/1483] dealing with unset attribute fields --- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/world/enumdelegate.cpp | 5 ++++- apps/opencs/view/world/enumdelegate.hpp | 3 ++- components/esm/loadskil.cpp | 15 +++++++++------ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index bc87728945..3be7228b31 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -61,7 +61,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) new CSVWorld::EnumDelegateFactory (sSpecialisations)); mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, - new CSVWorld::EnumDelegateFactory (sAttributes)); + new CSVWorld::EnumDelegateFactory (sAttributes, true)); } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 0dd0a1d594..b1e9f72865 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -92,10 +92,13 @@ void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewIte CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {} -CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names) +CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names, bool allowNone) { assert (names); + if (allowNone) + add (-1, ""); + for (int i=0; names[i]; ++i) add (i, names[i]); } diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index 752ed5be72..58f19ff782 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -47,8 +47,9 @@ namespace CSVWorld EnumDelegateFactory(); - EnumDelegateFactory (const char **names); + EnumDelegateFactory (const char **names, bool allowNone = false); ///< \param names Array of char pointer with a 0-pointer as end mark + /// \param allowNone Use value of -1 for "none selected" (empty string) virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b7259db94e..b57645f3b8 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -127,15 +127,18 @@ void Skill::save(ESMWriter &esm) { std::ostringstream stream; - stream << "#"; + if (index!=-1) + { + stream << "#"; - if (index<10) - stream << "0"; + if (index<10) + stream << "0"; - stream << index; + stream << index; - if (index>=0 && index=0 && index Date: Tue, 2 Apr 2013 14:20:51 +0200 Subject: [PATCH 0860/1483] added hidden flag column to faction table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 9345df0d20..dfabaaf2cf 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -409,6 +409,31 @@ namespace CSMWorld return true; } }; + + template + struct HiddenColumn : public Column + { + HiddenColumn() : Column ("Hidden", ColumnBase::Display_Boolean) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mIsHidden!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mIsHidden = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 23a1eb91b9..13fff7f096 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -60,6 +60,7 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + mFactions.addColumn (new HiddenColumn); for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); From 9d009af2a132823795dc949ed9b030e4a95e7a1e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 15:33:28 +0200 Subject: [PATCH 0861/1483] simplified code for sub view factory creation --- apps/opencs/view/world/subviews.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index cbfbf6b464..de36594a58 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -8,20 +8,24 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { - manager.add (CSMWorld::UniversalId::Type_Globals, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); - manager.add (CSMWorld::UniversalId::Type_Gmsts, new CSVDoc::SubViewFactoryWithCreateFlag (false)); manager.add (CSMWorld::UniversalId::Type_Skills, new CSVDoc::SubViewFactoryWithCreateFlag (false)); - manager.add (CSMWorld::UniversalId::Type_Classes, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); + static const CSMWorld::UniversalId::Type sTableTypes[] = + { + CSMWorld::UniversalId::Type_Globals, + CSMWorld::UniversalId::Type_Classes, + CSMWorld::UniversalId::Type_Factions, + + CSMWorld::UniversalId::Type_None // end marker + }; + + for (int i=0; sTableTypes[i]!=CSMWorld::UniversalId::Type_None; ++i) + manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreateFlag (true)); - manager.add (CSMWorld::UniversalId::Type_Factions, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); From 676a92e2e0157abe29fd898531b0c63610db0466 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 15:47:25 +0200 Subject: [PATCH 0862/1483] moved Verify function from World menu to File menu --- apps/opencs/view/doc/view.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3c4bc3b047..83b333c04e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -41,6 +41,10 @@ void CSVDoc::View::setupFileMenu() connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); + mVerify = new QAction (tr ("&Verify"), this); + connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); + file->addAction (mVerify); + QAction *close = new QAction (tr ("&Close"), this); connect (close, SIGNAL (triggered()), this, SLOT (close())); file->addAction(close); @@ -97,10 +101,6 @@ void CSVDoc::View::setupWorldMenu() QAction *factions = new QAction (tr ("Factions"), this); connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); world->addAction (factions); - - mVerify = new QAction (tr ("&Verify"), this); - connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); - world->addAction (mVerify); } void CSVDoc::View::setupUi() From 369cf0b4cafac002e0a0338163b95a29630f2b51 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 20:46:48 +0200 Subject: [PATCH 0863/1483] Enchanting price mechanics --- apps/openmw/mwgui/enchantingdialog.cpp | 27 ++++++++---------- apps/openmw/mwmechanics/enchanting.cpp | 38 +++++++++++++++++++++++++- apps/openmw/mwmechanics/enchanting.hpp | 2 ++ 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 0f3b8b7cb0..1ed80127d4 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -63,6 +63,8 @@ namespace MWGui mCastCost->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost())); + mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); + switch(mEnchanting.getEnchantType()) { case 0: @@ -86,16 +88,10 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { - - /*Now there's no need to use other enchanters, player is the enchanter here, - even if the enchanted object is created by NPC. Could be changed later, probably - with some price formulas */ - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(player); + mEnchanting.setEnchanter(actor); - mPtr = player; + mPtr = actor; startEditing (); } @@ -103,13 +99,14 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Ptr gem = soulgem; mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); mPtr = player; - startEditing(); + mEnchanting.setSoulGem(gem); } void EnchantingDialog::onReferenceUnavailable () @@ -252,12 +249,6 @@ namespace MWGui return; } - if (boost::lexical_cast(mPrice->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) - { - mWindowManager.messageBox ("#{sNotifyMessage18}"); - return; - } - if (mEnchanting.soulEmpty()) { mWindowManager.messageBox ("#{sNotifyMessage52}"); @@ -279,6 +270,12 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); + if (mEnchanting.getEnchantPrice() > mWindowManager.getInventoryWindow()->getPlayerGold()) + { + mWindowManager.messageBox ("#{sNotifyMessage18}"); + return; + } + int result = mEnchanting.create(); if(result==1) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d86f7c1511..a2f85fb0c4 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -3,6 +3,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" #include "npcstats.hpp" @@ -79,7 +80,10 @@ namespace MWMechanics MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); ref.getPtr().getRefData().setCount (mOldItemCount-1); - MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); + payForEnchantment(); return true; } @@ -126,6 +130,8 @@ namespace MWMechanics float cost = 0; std::vector mEffects = mEffectList.mList; int i=mEffects.size(); + if(i<=0) + return 0; /* Formula from http://www.uesp.net/wiki/Morrowind:Enchant @@ -155,6 +161,17 @@ namespace MWMechanics } return cost; } + + int Enchanting::getEnchantPrice() const + { + if(mEnchanter.isEmpty()) + return 0; + + float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->getFloat(); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantCost() * priceMultipler), true); + return price; + } + int Enchanting::getGemCharge() const { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -216,4 +233,23 @@ namespace MWMechanics } return (chance1-chance2); } + + void Enchanting::payForEnchantment() const + { + MWWorld::Ptr gold; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + + for (MWWorld::ContainerStoreIterator it = store.begin(); + it != store.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) + { + gold = *it; + } + } + + gold.getRefData().setCount(gold.getRefData().getCount() - getEnchantPrice()); + } } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index c951ae8256..d8a6342ac9 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -36,11 +36,13 @@ namespace MWMechanics void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) int getEnchantType() const; int getEnchantCost() const; + int getEnchantPrice() const; int getMaxEnchantValue() const; int getGemCharge() const; float getEnchantChance() const; bool soulEmpty() const; //Return true if empty bool itemEmpty() const; //Return true if empty + void payForEnchantment() const; }; } #endif From 98727d2fb6c6ec26a5f8dabe370d9714b23d71dd Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 21:32:23 +0200 Subject: [PATCH 0864/1483] Workaround for launcher compilation problems due to bug in Qt MOC compiler. For details please see: https://forum.openmw.org/viewtopic.php?f=7&t=1451 https://bugreports.qt-project.org/browse/QTBUG-22829 Signed-off-by: Lukasz Gromanowski --- apps/launcher/maindialog.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 7e818a74ab..824dff6e82 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -2,9 +2,9 @@ #define MAINDIALOG_H #include - +#ifndef Q_MOC_RUN #include - +#endif #include "settings/gamesettings.hpp" #include "settings/graphicssettings.hpp" #include "settings/launchersettings.hpp" From 7b7d3353a66fc30e6282c6d3931d012abbfa029e Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 22:23:38 +0200 Subject: [PATCH 0865/1483] Exception for enchanting with Azura Star --- apps/openmw/mwmechanics/enchanting.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index a2f85fb0c4..45db667d26 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -54,7 +54,12 @@ namespace MWMechanics { ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); - mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + + //Exception for Azura Star, it's not destroyed after enchanting + if(mSoulGemPtr.get()->mBase->mId=="Misc_SoulGem_Azura") + mSoulGemPtr.getCellRef().mSoul=""; + else + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { From 061fb4c482353633d2610166646a981998307a24 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:15:22 +0200 Subject: [PATCH 0866/1483] Added simple Travis CI cfg file. Added simple Travis CI configuration file for testing. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..94cf749245 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: cpp +compiler: + - clang + - gcc +before_script: + - mkdir build + - cd build + - cmake .. +branches: + only: + - master + - travis_ci_test +notifications: + recipients: + - lgromanowski+travis.ci@gmail.com + email: + on_success: change + on_failure: always From df8da0486da56835f55ab31e2aa87bfda82a50e0 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:20:59 +0200 Subject: [PATCH 0867/1483] Small changes in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 94cf749245..f2a9179f59 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,9 @@ before_script: - mkdir build - cd build - cmake .. +before_install: + - git submodule update --init --recursive +script: make branches: only: - master From cb18cf1eee9ab28ced4347aa880403972ed18dde Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:30:44 +0200 Subject: [PATCH 0868/1483] Added OpenMW dependencies into .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f2a9179f59..6e3748056c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,10 @@ before_script: - cd build - cmake .. before_install: - - git submodule update --init --recursive + - git submodule update --init --recursive + - sudo apt-add-repository ppa:openmw/deps + - sudo apt-get update -qq + - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make branches: only: From 4f19fb0cdbfa5ac3815f83133cb1d864f371274a Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:38:23 +0200 Subject: [PATCH 0869/1483] Changes in apt-add-repository line - added echo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6e3748056c..cdbabb1a1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_script: - cmake .. before_install: - git submodule update --init --recursive - - sudo apt-add-repository ppa:openmw/deps + - echo -e "\n" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make From f8497895149469720e56c25fc0b9b25e08e3c058 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:41:24 +0200 Subject: [PATCH 0870/1483] Changes in apt-add-repository line. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cdbabb1a1e..3d3ad404c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_script: - cmake .. before_install: - git submodule update --init --recursive - - echo -e "\n" | sudo apt-add-repository ppa:openmw/deps + - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make From df0ee82a3c9f27700ee39ac5175a01fc77912b7a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Apr 2013 23:45:32 +0200 Subject: [PATCH 0871/1483] Loose files should have priority over BSA resources. This makes texture replacers work. --- apps/openmw/engine.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ce84b8dfe1..dad024c98e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -153,20 +153,6 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { - for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) - { - if (mFileCollections.doesExist(*archive)) - { - const std::string archivePath = mFileCollections.getPath(*archive).string(); - std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath); - } - else - { - std::cout << "Archive " << *archive << " not found" << std::endl; - } - } - const Files::PathContainer& dataDirs = mFileCollections.getPaths(); std::string dataDirectory; for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) @@ -175,6 +161,24 @@ void OMW::Engine::loadBSA() std::cout << "Data dir " << dataDirectory << std::endl; Bsa::addDir(dataDirectory, mFSStrict); } + + // BSA resources are put into a separate group. We want loose files to have priority over BSA resources, and this seems + // to be the only way to get Ogre to do just that. + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup ("GroupBSA"); + + for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) + { + if (mFileCollections.doesExist(*archive)) + { + const std::string archivePath = mFileCollections.getPath(*archive).string(); + std::cout << "Adding BSA archive " << archivePath << std::endl; + Bsa::addBSA(archivePath, "GroupBSA"); + } + else + { + std::cout << "Archive " << *archive << " not found" << std::endl; + } + } } // add resources directory From 73b984cc2d01ccca61cd5efeaa51f324060e69d9 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:08:24 +0200 Subject: [PATCH 0872/1483] Corrected packages names in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3d3ad404c5..75fe322990 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev mygui-static-dev script: make branches: only: From c32f4d853e6ca6b9f5f06367ad526f911c034bfb Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:14:26 +0200 Subject: [PATCH 0873/1483] Another change in packages names in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 75fe322990..a29140b256 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev mygui-static-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev script: make branches: only: From c73209c049b4ba2776fb8c11ae91132dba8515a8 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:21:42 +0200 Subject: [PATCH 0874/1483] Added another part of dependencies, enabled building with static ogre and mygui. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a29140b256..1239f1ed0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,12 @@ compiler: before_script: - mkdir build - cd build - - cmake .. + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev script: make branches: only: From 05a5cb3ae48e00d82488d2d4056a5fd906cde571 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 00:27:29 +0200 Subject: [PATCH 0875/1483] Improved responsiveness of the inventory window when resizing. --- apps/openmw/engine.cpp | 1 + apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/inventorywindow.cpp | 20 +++++++++++++++----- apps/openmw/mwgui/inventorywindow.hpp | 4 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dad024c98e..948a06d471 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -66,6 +66,7 @@ bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) { if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame); + MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame); return true; } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4d66a77423..b271aed182 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -246,6 +246,8 @@ namespace MWBase virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; + virtual void frameStarted(float dt) = 0; + virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1943ff773a..aeab5f94aa 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -37,6 +37,7 @@ namespace MWGui , mLastXSize(0) , mLastYSize(0) , mPreview(MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()) + , mPreviewDirty(true) { static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); @@ -268,6 +269,19 @@ namespace MWGui mTrading = true; } + void InventoryWindow::doRenderUpdate () + { + if (mPreviewDirty) + { + mPreviewDirty = false; + MyGUI::IntSize size = mAvatar->getSize(); + + mPreview.update (size.width, size.height); + mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); + mAvatarImage->setImageTexture("CharacterPreview"); + } + } + void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory @@ -282,11 +296,7 @@ namespace MWGui else mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability - MyGUI::IntSize size = mAvatar->getSize(); - - mPreview.update (size.width, size.height); - mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); - mAvatarImage->setImageTexture("CharacterPreview"); + mPreviewDirty = true; mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + boost::lexical_cast(static_cast(MWWorld::Class::get(mPtr).getArmorRating(mPtr)))); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 95657672d3..fceb7ecef1 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -16,6 +16,8 @@ namespace MWGui virtual void open(); + void doRenderUpdate(); + /// start trading, disables item drag&drop void startTrade(); @@ -34,6 +36,8 @@ namespace MWGui } protected: + bool mPreviewDirty; + MyGUI::Widget* mAvatar; MyGUI::ImageBox* mAvatarImage; MyGUI::TextBox* mArmorRating; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cf14c1f514..c975b2cdba 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1190,3 +1190,8 @@ void WindowManager::showSoulgemDialog(MWWorld::Ptr item) { mSoulgemDialog->show(item); } + +void WindowManager::frameStarted (float dt) +{ + mInventoryWindow->doRenderUpdate (); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7a7adec27d..c14c6b2fe4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -238,6 +238,8 @@ namespace MWGui virtual void startRepair(MWWorld::Ptr actor); virtual void startRepairItem(MWWorld::Ptr item); + virtual void frameStarted(float dt); + virtual void showSoulgemDialog (MWWorld::Ptr item); virtual void changePointer (const std::string& name); From 5a1bb21b23b1c68a1ea597ac339396a0a2704aee Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:30:43 +0200 Subject: [PATCH 0876/1483] Build dependecies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1239f1ed0e..80c3a46537 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools script: make branches: only: From 74d519d4057fe9d06c4b3b0fe3d6d1cafb074390 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:35:18 +0200 Subject: [PATCH 0877/1483] Added libois into build dependencies in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 80c3a46537..51fa23e8e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools libois-dev script: make branches: only: From 798ed642030dc059e0ab4d4963061bffb07131b6 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:40:01 +0200 Subject: [PATCH 0878/1483] Added google-mock and libopenal into build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 51fa23e8e6..003a4d8013 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools libois-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev script: make branches: only: From 5957a9e037942934b30202b572ed9d8bb0cb4876 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:44:03 +0200 Subject: [PATCH 0879/1483] Added libxaw7 into dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 003a4d8013..4939ad0ec7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From e7bb3743cc491d00e036791d6f74ccf512d92286 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:58:59 +0200 Subject: [PATCH 0880/1483] Trying to build with Ogre shared lib . Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4939ad0ec7..d31e4afc8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,12 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 + - cmake .. -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From f6f165852dda10d098f2f8daa2ee9081291329fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Apr 2013 21:08:21 -0700 Subject: [PATCH 0881/1483] Better handle material texture layers --- components/nifogre/ogrenifloader.cpp | 110 ++++++++++++++++----------- 1 file changed, 67 insertions(+), 43 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 5aa5ff80cb..b3ab4c0160 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -538,16 +538,51 @@ static std::map MaterialMap; static void warn(const std::string &msg) { - std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; } static void fail(const std::string &msg) { - std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; abort(); } +static std::string findTextureName(const std::string &filename) +{ + /* Bethesda 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. + */ + static const char path[] = "textures\\"; + + std::string texname = filename; + Misc::StringUtils::toLower(texname); + + if(texname.compare(0, sizeof(path)-1, path) != 0) + texname = path + texname; + + Ogre::String::size_type pos = texname.rfind('.'); + if(pos != Ogre::String::npos && texname.compare(pos, texname.length() - pos, ".dds") != 0) + { + // since we know all (GOTY edition or less) textures end + // in .dds, we change the extension + texname.replace(pos, texname.length(), ".dds"); + + // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) + // verify, and revert if false (this call succeeds quickly, but fails slowly) + if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texname)) + { + texname = filename; + Misc::StringUtils::toLower(texname); + if(texname.compare(0, sizeof(path)-1, path) != 0) + texname = path + texname; + } + } + + return texname; +} + public: static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, @@ -575,47 +610,29 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int depthFlags = 3; // Default should be 1, but Bloodmoon's models are broken int specFlags = 0; - Ogre::String texName; + Ogre::String texName[7]; bool vertexColour = (shape->data->colors.size() != 0); // Texture - if(texprop && texprop->textures[0].inUse) + if(texprop) { - const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); - if(st->external) + for(int i = 0;i < 7;i++) { - /* Bethesda 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. - */ - static const char path[] = "textures\\"; - - texName = st->filename; - Misc::StringUtils::toLower(texName); - - if(texName.compare(0, sizeof(path)-1, path) != 0) - texName = path + texName; - - Ogre::String::size_type pos = texName.rfind('.'); - if(pos != Ogre::String::npos && texName.compare(pos, texName.length() - pos, ".dds") != 0) + if(!texprop->textures[i].inUse) + continue; + if(texprop->textures[i].texture.empty()) { - // since we know all (GOTY edition or less) textures end - // in .dds, we change the extension - texName.replace(pos, texName.length(), ".dds"); - - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - { - texName = st->filename; - Misc::StringUtils::toLower(texName); - if(texName.compare(0, sizeof(path)-1, path) != 0) - texName = path + texName; - } + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name+"\n"); + continue; } + + const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); + if(st->external) + texName[i] = findTextureName(st->filename); + else + warn("Found internal texture, ignoring."); } - else warn("Found internal texture, ignoring."); } // Alpha modifiers @@ -655,8 +672,6 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String alpha = matprop->data.alpha; } - Ogre::String matname = name; - if(matprop || !texName.empty()) { // Generate a hash out of all properties that can affect the material. size_t h = 0; @@ -672,7 +687,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, emissive.x); boost::hash_combine(h, emissive.y); boost::hash_combine(h, emissive.z); - boost::hash_combine(h, texName); + for(int i = 0;i < 7;i++) + { + if(!texName[i].empty()) + boost::hash_combine(h, texName[i]); + } boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); @@ -687,11 +706,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String return itr->second; } // not found, create a new one - MaterialMap.insert(std::make_pair(h, matname)); + MaterialMap.insert(std::make_pair(h, name)); } // No existing material like this. Create a new one. - sh::MaterialInstance* instance = sh::Factory::getInstance ().createMaterialInstance (matname, "openmw_objects_base"); + sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); if(vertMode == 0 || !vertexColour) { instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); @@ -722,13 +741,18 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } - instance->setProperty("diffuseMap", sh::makeProperty(texName)); + instance->setProperty("diffuseMap", sh::makeProperty(texName[0])); + for(int i = 1;i < 7;i++) + { + if(!texName[i].empty()) + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); + } if (vertexColour) instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Add transparency if NiAlphaProperty was present - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); if (result.first) { alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ @@ -763,8 +787,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); // depth_func??? - sh::Factory::getInstance()._ensureMaterial(matname, "Default"); - return matname; + sh::Factory::getInstance()._ensureMaterial(name, "Default"); + return name; } }; From 512534be11a670c0102299bad95fa61264d3e604 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Apr 2013 22:58:07 -0700 Subject: [PATCH 0882/1483] Read the correct texture resource for other layers --- components/nifogre/ogrenifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index b3ab4c0160..d1ce7ae318 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -627,7 +627,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String continue; } - const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); + const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); if(st->external) texName[i] = findTextureName(st->filename); else From aac2ba1d5fff2e3b4ebfe22125343ac7aa027b62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 12:24:13 +0200 Subject: [PATCH 0883/1483] Fix loading screen looking for wallpapers in a fixed group. --- apps/openmw/mwgui/loadingscreen.cpp | 20 +++++++++++++------- apps/openmw/mwgui/loadingscreen.hpp | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index e7c7acb533..86f196d9f5 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -217,15 +217,21 @@ namespace MWGui void LoadingScreen::changeWallpaper () { - if (mResources.isNull ()) - mResources = Ogre::ResourceGroupManager::getSingleton ().findResourceNames ("General", "Splash_*.tga"); - - - if (mResources->size()) + if (mResources.empty()) { - std::string const & randomSplash = mResources->at (rand() % mResources->size()); + Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); + for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + { + Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash_*.tga"); + mResources.insert(mResources.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); + } + } - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); + if (!mResources.empty()) + { + std::string const & randomSplash = mResources.at (rand() % mResources.size()); + + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); mBackgroundImage->setImageTexture (randomSplash); } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 24b3850710..176fc0f5d5 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -44,7 +44,7 @@ namespace MWGui Ogre::Rectangle2D* mRectangle; Ogre::MaterialPtr mBackgroundMaterial; - Ogre::StringVectorPtr mResources; + Ogre::StringVector mResources; bool mLoadingOn; From 095daca058e980471af9391b027e0f83f28c494b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 03:26:21 -0700 Subject: [PATCH 0884/1483] Create entities when iterating through the NIF --- components/nifogre/ogrenifloader.cpp | 185 ++++++++++++--------------- components/nifogre/ogrenifloader.hpp | 14 -- 2 files changed, 79 insertions(+), 120 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d1ce7ae318..89f55fbd4e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1088,9 +1088,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader typedef std::map LoaderMap; static LoaderMap sLoaders; -public: - NIFMeshLoader() - { } + NIFMeshLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1113,25 +1111,25 @@ public: findTriShape(mesh, node, NULL, NULL, NULL, NULL, NULL, NULL); } - void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) + void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) { // Do not create meshes for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) return; - flags |= node->flags; - // Marker objects: just skip the entire node /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) return; + flags |= node->flags; + Nif::ExtraPtr e = node->extra; while(!e.empty()) { - Nif::NiStringExtraData *sd; - if((sd=dynamic_cast(e.getPtr())) != NULL) + if(e->recType == Nif::RC_NiStringExtraData) { + const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj if(sd->string == "MRK") @@ -1146,7 +1144,7 @@ public: if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { - const Nif::NiTriShape *shape = dynamic_cast(node); + const Nif::NiTriShape *shape = static_cast(node); Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); @@ -1165,7 +1163,15 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), shape->name)); + entities.mEntities.push_back(sceneMgr->createEntity(mesh)); + if(entities.mSkelBase) + { + Ogre::Entity *entity = entities.mEntities.back(); + if(entity->hasSkeleton()) + entity->shareSkeletonInstanceWith(entities.mSkelBase); + else + entities.mSkelBase->attachObjectToBone(shape->name, entity); + } } const Nif::NiNode *ninode = dynamic_cast(node); @@ -1175,12 +1181,12 @@ public: for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createMeshes(children[i].getPtr(), meshes, flags); + createEntities(sceneMgr, children[i].getPtr(), entities, flags); } } } - void createEmptyMesh(const Nif::Node *node, MeshInfoList &meshes) + void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all @@ -1199,91 +1205,61 @@ public: mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), node->name)); + entities.mSkelBase = sceneMgr->createEntity(mesh); + entities.mEntities.push_back(entities.mSkelBase); + } + +public: + NIFMeshLoader() : mShapeIndex(~(size_t)0) + { } + + static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) + { + Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); + Nif::NIFFile &nif = *pnif.get(); + if(nif.numRecords() < 1) + { + nif.warn("Found no NIF records in "+name+"."); + return; + } + + // The first record is assumed to be the root node + const Nif::Record *r = nif.getRecord(0); + assert(r != NULL); + + const Nif::Node *node = dynamic_cast(r); + if(node == NULL) + { + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return; + } + + bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); + if(!hasSkel) + hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); + + NIFMeshLoader meshldr(name, group); + if(hasSkel) + meshldr.createSkelBase(sceneMgr, node, entities); + meshldr.createEntities(sceneMgr, node, entities); } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -typedef std::map MeshInfoMap; -static MeshInfoMap sMeshInfoMap; - -MeshInfoList Loader::load(const std::string &name, const std::string &group) -{ - MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name); - if(meshiter != sMeshInfoMap.end()) - return meshiter->second; - - MeshInfoList &meshes = sMeshInfoMap[name]; - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) - { - nif.warn("Found no NIF records in "+name+"."); - return meshes; - } - - // The first record is assumed to be the root node - Nif::Record const *r = nif.getRecord(0); - assert(r != NULL); - - Nif::Node const *node = dynamic_cast(r); - if(node == NULL) - { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return meshes; - } - - bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); - if(!hasSkel) - hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - - NIFMeshLoader meshldr(name, group); - if(hasSkel) - meshldr.createEmptyMesh(node, meshes); - meshldr.createMeshes(node, meshes, 0); - - return meshes; -} - EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, group); - if(meshes.size() == 0) - return entitylist; + NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); - Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - for(size_t i = 0;i < meshes.size();i++) + for(size_t i = 0;i < entitylist.mEntities.size();i++) { - entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].mMeshName)); - Ogre::Entity *entity = entitylist.mEntities.back(); - if(!entitylist.mSkelBase && entity->hasSkeleton()) - entitylist.mSkelBase = entity; - } - - if(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(entitylist.mSkelBase); - parentNode->attachObject(entity); - } - else if(entity != entitylist.mSkelBase) - entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - } - } - else - { - for(size_t i = 0;i < entitylist.mEntities.size();i++) - parentNode->attachObject(entitylist.mEntities[i]); + Ogre::Entity *entity = entitylist.mEntities[i]; + if(!entity->isAttached()) + parentNode->attachObject(entity); } return entitylist; @@ -1296,25 +1272,17 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, group); - if(meshes.size() == 0) - return entitylist; + NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); bool isskinned = false; - Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = "@shape=tri "+bonename; - Misc::StringUtils::toLower(filter); - for(size_t i = 0;i < meshes.size();i++) + for(size_t i = 0;i < entitylist.mEntities.size();i++) { - Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); - if(!entitylist.mSkelBase) + Ogre::Entity *ent = entitylist.mEntities[i]; + if(entitylist.mSkelBase != ent && ent->hasSkeleton()) { - if(ent->hasSkeleton()) - entitylist.mSkelBase = ent; - } - else if(!isskinned && ent->hasSkeleton()) isskinned = true; - entitylist.mEntities.push_back(ent); + break; + } } Ogre::Vector3 scale(1.0f); @@ -1323,20 +1291,21 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(isskinned) { + std::string filter = "@shape=tri "+bonename; + Misc::StringUtils::toLower(filter); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity->hasSkeleton()) { - if(entity != entitylist.mSkelBase) - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - if(entity->getMesh()->getName().find(filter) != std::string::npos) + if(entity == entitylist.mSkelBase || + entity->getMesh()->getName().find(filter) != std::string::npos) parentNode->attachObject(entity); } else { - if(entity->getMesh()->getName().find(filter) != std::string::npos) - entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + if(entity->getMesh()->getName().find(filter) == std::string::npos) + entity->detachFromParent(); } } } @@ -1344,8 +1313,12 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen { for(size_t i = 0;i < entitylist.mEntities.size();i++) { - Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entitylist.mEntities[i]); - tag->setScale(scale); + Ogre::Entity *entity = entitylist.mEntities[i]; + if(!entity->isAttached()) + { + Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); + tag->setScale(scale); + } } } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index b8b2e3c007..92b153468a 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -48,22 +48,8 @@ struct EntityList { }; -/* This holds a list of mesh names, the names of their parent nodes, and the offset - * from their parent nodes. */ -struct MeshInfo { - std::string mMeshName; - std::string mTargetNode; - - MeshInfo(const std::string &name, const std::string &target) - : mMeshName(name), mTargetNode(target) - { } -}; -typedef std::vector MeshInfoList; - class Loader { - static MeshInfoList load(const std::string &name, const std::string &group); - public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, From f0d49fdbd06f99a297bb39c80b0b14317aade26e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 12:28:57 +0200 Subject: [PATCH 0885/1483] Create separate groups for each data dir / BSA file. --- apps/openmw/engine.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 948a06d471..17610e479f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -154,26 +154,36 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { + // We use separate resource groups to handle location priority. const Files::PathContainer& dataDirs = mFileCollections.getPaths(); - std::string dataDirectory; + + int i=0; for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { - dataDirectory = iter->string(); + // Last data dir has the highest priority + std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i); + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); + + std::string dataDirectory = iter->string(); std::cout << "Data dir " << dataDirectory << std::endl; - Bsa::addDir(dataDirectory, mFSStrict); + Bsa::addDir(dataDirectory, mFSStrict, groupName); + ++i; } - // BSA resources are put into a separate group. We want loose files to have priority over BSA resources, and this seems - // to be the only way to get Ogre to do just that. - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup ("GroupBSA"); - + i=0; for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) { if (mFileCollections.doesExist(*archive)) { + // Last BSA has the highest priority + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(dataDirs.size()-i); + + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); + const std::string archivePath = mFileCollections.getPath(*archive).string(); std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath, "GroupBSA"); + Bsa::addBSA(archivePath, groupName); + ++i; } else { From 5625d73d84488a2c4eb2ff51270329a972733285 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 17:16:34 +0200 Subject: [PATCH 0886/1483] Bump texture support --- components/nif/property.hpp | 11 ++ components/nifogre/ogrenifloader.cpp | 26 ++++- extern/shiny/Docs/Macros.dox | 23 ++++- extern/shiny/Main/MaterialInstance.hpp | 1 + extern/shiny/Main/ShaderInstance.cpp | 15 +-- extern/shiny/Main/ShaderSet.cpp | 16 +++ extern/shiny/Main/ShaderSet.hpp | 4 + files/materials/objects.mat | 7 ++ files/materials/objects.shader | 134 +++++++++++++++++++++++-- 9 files changed, 211 insertions(+), 26 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index cd1e0a5d11..00cdc0e008 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -109,6 +109,17 @@ public: * 5 - Bump map texture * 6 - Decal texture */ + enum TextureType + { + BaseTexture = 0, + DarkTexture = 1, + DetailTexture = 2, + GlossTexture = 3, + GlowTexture = 4, + BumpTexture = 5, + DecalTexture = 6 + }; + Texture textures[7]; void read(NIFStream *nif) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 89f55fbd4e..c5dc7fbb98 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -555,11 +555,14 @@ static std::string findTextureName(const std::string &filename) * texture file name references were kept as .tga. */ static const char path[] = "textures\\"; + static const char path2[] = "textures/"; + std::string texname = filename; Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0) + if(texname.compare(0, sizeof(path)-1, path) != 0 + && texname.compare(0, sizeof(path2)-1, path2) != 0) texname = path + texname; Ogre::String::size_type pos = texname.rfind('.'); @@ -575,7 +578,8 @@ static std::string findTextureName(const std::string &filename) { texname = filename; Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0) + if(texname.compare(0, sizeof(path)-1, path) != 0 + && texname.compare(0, sizeof(path2)-1, path2) != 0) texname = path + texname; } } @@ -590,7 +594,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String const Nif::NiAlphaProperty *alphaprop, const Nif::NiVertexColorProperty *vertprop, const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + const Nif::NiSpecularProperty *specprop, + bool &needTangents) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -634,6 +639,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String warn("Found internal texture, ignoring."); } } + needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); // Alpha modifiers if(alphaprop) @@ -741,7 +747,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } - instance->setProperty("diffuseMap", sh::makeProperty(texName[0])); + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); for(int i = 1;i < 7;i++) { if(!texName[i].empty()) @@ -1022,11 +1029,20 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } + bool needTangents=false; std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup, texprop, matprop, alphaprop, - vertprop, zprop, specprop); + vertprop, zprop, specprop, needTangents); if(matname.length() > 0) sub->setMaterialName(matname); + + // build tangents if the material needs them + if (needTangents) + { + unsigned short src,dest; + if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) + mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); + } } bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, diff --git a/extern/shiny/Docs/Macros.dox b/extern/shiny/Docs/Macros.dox index 0578c447f3..c04ebd3747 100644 --- a/extern/shiny/Docs/Macros.dox +++ b/extern/shiny/Docs/Macros.dox @@ -107,6 +107,23 @@ \section properties Property retrieval / binding + \subsection shPropertyHasValue shPropertyHasValue + + Usage: \@shPropertyHasValue(property) + + Gets replaced by 1 if the property's value is not empty, or 0 if it is empty. + Useful for checking whether an optional texture is present or not. + + Example: + \code + #if @shPropertyHasValue(specularMap) + // specular mapping code + #endif + #if @shPropertyHasValue(normalMap) + // normal mapping code + #endif + \endcode + \subsection shUniformProperty shUniformProperty Usage: \@shUniformProperty<4f|3f|2f|1f|int> (uniformName, property) @@ -130,15 +147,11 @@ Example: \code - #if @shPropertyBool(has_normal_map) + #if @shPropertyBool(has_vertex_colors) ... #endif \endcode - \subsection shPropertyNotBool shPropertyNotBool - - Same as shPropertyBool, but inverts the result (i.e. when shPropertyBool would return 0, this returns 1 and vice versa) - \subsection shPropertyString shPropertyString Retrieve a string property of the pass that this shader belongs to diff --git a/extern/shiny/Main/MaterialInstance.hpp b/extern/shiny/Main/MaterialInstance.hpp index 000f9d60c9..36ba37ddba 100644 --- a/extern/shiny/Main/MaterialInstance.hpp +++ b/extern/shiny/Main/MaterialInstance.hpp @@ -25,6 +25,7 @@ namespace sh public: virtual void requestedConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called before creating virtual void createdConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called after creating + virtual ~MaterialInstanceListener(){} }; /** diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp index 1539128aba..b44c63c322 100644 --- a/extern/shiny/Main/ShaderInstance.cpp +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -194,13 +194,6 @@ namespace sh bool val = retrieveValue(value, properties->getContext()).get(); replaceValue = val ? "1" : "0"; } - else if (cmd == "shPropertyNotBool") // same as above, but inverts the result - { - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - bool val = retrieveValue(value, properties->getContext()).get(); - replaceValue = val ? "0" : "1"; - } else if (cmd == "shPropertyString") { std::string propertyName = args[0]; @@ -214,6 +207,14 @@ namespace sh std::string value = retrieveValue(properties->getProperty(propertyName), properties->getContext()).get(); replaceValue = (value == comparedAgainst) ? "1" : "0"; } + else if (isCmd(source, pos, "@shPropertyHasValue")) + { + assert(args.size() == 1); + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + std::string val = retrieveValue(value, properties->getContext()).get(); + replaceValue = (val.empty() ? "0" : "1"); + } else throw std::runtime_error ("unknown command \"" + cmd + "\""); source.replace(pos, (end+1)-pos, replaceValue); diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp index 413d7d1a26..628e0acee7 100644 --- a/extern/shiny/Main/ShaderSet.cpp +++ b/extern/shiny/Main/ShaderSet.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Factory.hpp" @@ -26,6 +27,10 @@ namespace sh std::ifstream stream(sourceFile.c_str(), std::ifstream::in); std::stringstream buffer; + boost::filesystem::path p (sourceFile); + p = p.branch_path(); + mBasePath = p.string(); + buffer << stream.rdbuf(); stream.close(); mSource = buffer.str(); @@ -52,6 +57,12 @@ namespace sh size_t start = currentToken.find('(')+1; mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start)); } + else if (boost::starts_with(currentToken, "@shPropertyHasValue")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); + size_t start = currentToken.find('(')+1; + mPropertiesToExist.push_back(currentToken.substr(start, currentToken.find(')')-start)); + } else if (boost::starts_with(currentToken, "@shPropertyEqual")) { assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos) @@ -135,6 +146,11 @@ namespace sh { boost::hash_combine(seed, retrieveValue(currentGlobalSettings->getProperty(*it), NULL).get()); } + for (std::vector::iterator it = mPropertiesToExist.begin(); it != mPropertiesToExist.end(); ++it) + { + std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); + boost::hash_combine(seed, static_cast(v != "")); + } boost::hash_combine(seed, static_cast(Factory::getInstance().getCurrentLanguage())); return seed; } diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp index a423b6779f..b21278ac99 100644 --- a/extern/shiny/Main/ShaderSet.hpp +++ b/extern/shiny/Main/ShaderSet.hpp @@ -53,6 +53,10 @@ namespace sh std::vector mGlobalSettings; ///< names of the global settings that affect the shader source std::vector mProperties; ///< names of the per-material properties that affect the shader source + std::vector mPropertiesToExist; + ///< same as mProperties, however in this case, it is only relevant if the property is empty or not + /// (we don't care about the value) + ShaderInstanceMap mInstances; ///< maps permutation ID (generated from the properties) to \a ShaderInstance void parse(); ///< find out which properties and global settings affect the shader source diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 5e18a666a7..00b43a9d0d 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -6,6 +6,7 @@ material openmw_objects_base emissive 0.0 0.0 0.0 vertmode 0 diffuseMap black.png + normalMap is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default @@ -22,6 +23,7 @@ material openmw_objects_base { vertexcolor_mode $vertmode is_transparent $is_transparent + normalMap $normalMap } diffuse $diffuse @@ -38,6 +40,11 @@ material openmw_objects_base direct_texture $diffuseMap create_in_ffp true } + + texture_unit normalMap + { + direct_texture $normalMap + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index c8616e9d1e..73968a6b3e 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -14,13 +14,15 @@ #define NEED_DEPTH #endif +#define NORMAL_MAP @shPropertyHasValue(normalMap) + +// if normal mapping is enabled, we force pixel lighting +#define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) #define UNDERWATER @shGlobalSettingBool(render_refraction) #define VERTEXCOLOR_MODE @shPropertyString(vertexcolor_mode) -#define VERTEX_LIGHTING 1 - #define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) #ifdef SH_VERTEX_SHADER @@ -42,6 +44,16 @@ shVertexInput(float2, uv0) shOutput(float2, UV) shNormalInput(float4) + +#if NORMAL_MAP + shTangentInput(float4) + shOutput(float3, tangentPassthrough) +#endif + +#if !VERTEX_LIGHTING + shOutput(float3, normalPassthrough) +#endif + #ifdef NEED_DEPTH shOutput(float, depthPassthrough) #endif @@ -52,6 +64,10 @@ shColourInput(float4) #endif +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + shOutput(float4, colourPassthrough) +#endif + #if VERTEX_LIGHTING shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) @@ -94,6 +110,15 @@ { shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; +#if NORMAL_MAP + tangentPassthrough = tangent.xyz; +#endif +#if !VERTEX_LIGHTING + normalPassthrough = normal.xyz; +#endif +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + colourPassthrough = colour; +#endif #ifdef NEED_DEPTH @@ -188,15 +213,31 @@ #endif SH_BEGIN_PROGRAM - shSampler2D(diffuseMap) - shInput(float2, UV) + shSampler2D(diffuseMap) + +#if NORMAL_MAP + shSampler2D(normalMap) +#endif + + shInput(float2, UV) + +#if NORMAL_MAP + shInput(float3, tangentPassthrough) +#endif +#if !VERTEX_LIGHTING + shInput(float3, normalPassthrough) +#endif #ifdef NEED_DEPTH shInput(float, depthPassthrough) #endif shInput(float3, objSpacePositionPassthrough) - + +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + shInput(float4, colourPassthrough) +#endif + #if FOG shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) @@ -222,23 +263,98 @@ #if (UNDERWATER) || (FOG) shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) - shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) + shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) #endif #if UNDERWATER - shUniform(float, waterLevel) @shSharedParameter(waterLevel) + shUniform(float, waterLevel) @shSharedParameter(waterLevel) shUniform(float, waterEnabled) @shSharedParameter(waterEnabled) #endif #if VERTEX_LIGHTING shInput(float4, lightResult) shInput(float3, directionalResult) +#else + shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) + shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) + shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) + #if VERTEXCOLOR_MODE != 2 + shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) + #endif + #if VERTEXCOLOR_MODE != 2 + shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) + #endif + #if VERTEXCOLOR_MODE != 1 + shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + #endif #endif SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV); - + +#if NORMAL_MAP + float3 normal = normalPassthrough; + float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); + float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); + + #if SH_GLSL + tbn = transpose(tbn); + #endif + + float3 TSnormal = shSample(normalMap, UV.xy).xyz * 2 - 1; + + normal = normalize (shMatrixMult( transpose(tbn), TSnormal )); +#endif + +#if !VERTEX_LIGHTING + float3 viewPos = shMatrixMult(worldView, float4(objSpacePositionPassthrough,1)).xyz; + float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); + + float3 lightDir; + float d; + float4 lightResult = float4(0,0,0,1); + @shForeach(@shGlobalSettingString(num_lights)) + lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); + d = length(lightDir); + lightDir = normalize(lightDir); + +#if VERTEXCOLOR_MODE == 2 + lightResult.xyz += colourPassthrough.xyz * lightDiffuse[@shIterator].xyz + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * max(dot(viewNormal.xyz, lightDir), 0); +#else + lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * max(dot(viewNormal.xyz, lightDir), 0); +#endif + +#if @shIterator == 0 + float3 directionalResult = lightResult.xyz; +#endif + + @shEndForeach + + +#if VERTEXCOLOR_MODE == 2 + lightResult.xyz += lightAmbient.xyz * colourPassthrough.xyz + materialEmissive.xyz; + lightResult.a *= colourPassthrough.a; +#endif +#if VERTEXCOLOR_MODE == 1 + lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + colourPassthrough.xyz; +#endif +#if VERTEXCOLOR_MODE == 0 + lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; +#endif + +#if VERTEXCOLOR_MODE != 2 + lightResult.a *= materialDiffuse.a; +#endif +#endif + // shadows only for the first (directional) light #if SHADOWS float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); @@ -275,7 +391,7 @@ #if FOG float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - + #if UNDERWATER shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); From ae3e4ecf8b7598a021970ab2c3f1a75650822781 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:02:30 +0200 Subject: [PATCH 0887/1483] Finished enchanting --- apps/openmw/mwgui/enchantingdialog.cpp | 20 ++++++++++++++++++-- apps/openmw/mwgui/enchantingdialog.hpp | 1 + apps/openmw/mwmechanics/enchanting.cpp | 3 ++- files/mygui/openmw_enchanting_dialog.layout | 4 ++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 1ed80127d4..23e400c367 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -32,6 +32,7 @@ namespace MWGui getWidget(mTypeButton, "TypeButton"); getWidget(mBuyButton, "BuyButton"); getWidget(mPrice, "PriceLabel"); + getWidget(mPriceText, "PriceTextLabel"); setWidgets(mAvailableEffectsList, mUsedEffectsView); @@ -94,19 +95,34 @@ namespace MWGui mPtr = actor; startEditing (); + + mPrice->setVisible(true); } void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::Ptr gem = soulgem; mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); mPtr = player; startEditing(); - mEnchanting.setSoulGem(gem); + mEnchanting.setSoulGem(soulgem); + + MyGUI::ImageBox* image = mSoulBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(soulgem).getInventoryIcon(soulgem); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture (path); + image->setUserString ("ToolTipType", "ItemPtr"); + image->setUserData(soulgem); + image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); + + mPrice->setVisible(false); + mPriceText->setVisible(false); } void EnchantingDialog::onReferenceUnavailable () diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 347b37e908..a7861c422d 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -56,6 +56,7 @@ namespace MWGui MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; MyGUI::TextBox* mPrice; + MyGUI::TextBox* mPriceText; MWMechanics::Enchanting mEnchanting; ESM::EffectList mEffectList; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 45db667d26..884c4d8963 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -88,7 +88,8 @@ namespace MWMechanics MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); - payForEnchantment(); + if(!mSelfEnchanting) + payForEnchantment(); return true; } diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 41b8ffa938..f64d21deaa 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -97,11 +97,11 @@ - + - + From 21796197217e50a3cffe24f95008a46edd42da62 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:06:11 +0200 Subject: [PATCH 0888/1483] Small enchanting fix --- apps/openmw/mwgui/enchantingdialog.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 23e400c367..276e7a9047 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -95,8 +95,6 @@ namespace MWGui mPtr = actor; startEditing (); - - mPrice->setVisible(true); } void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) @@ -123,6 +121,7 @@ namespace MWGui mPrice->setVisible(false); mPriceText->setVisible(false); + updateLabels(); } void EnchantingDialog::onReferenceUnavailable () From 30654a1faa0d9181e4beb28babfd09fd801b809b Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:11:57 +0200 Subject: [PATCH 0889/1483] Added removing of ogre static. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d31e4afc8d..f517a4da83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq + - sudo apt-get remove -qq libogre-static-dev - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: From 4bf87948a03e6073c2c527c25f7ee45d7ba47c18 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:19:46 +0200 Subject: [PATCH 0890/1483] Removed clang compilation target. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f517a4da83..4852efb810 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: cpp compiler: - - clang - gcc before_script: - mkdir build From 08e9bb0236447d7a952f13791180ba122a5fad4a Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:25:40 +0200 Subject: [PATCH 0891/1483] Another small enchanting fix --- apps/openmw/mwmechanics/enchanting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 884c4d8963..d92acdafc0 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -7,6 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include namespace MWMechanics { @@ -56,7 +57,7 @@ namespace MWMechanics enchantment.mData.mCharge = getGemCharge(); //Exception for Azura Star, it's not destroyed after enchanting - if(mSoulGemPtr.get()->mBase->mId=="Misc_SoulGem_Azura") + if(boost::iequals(mSoulGemPtr.get()->mBase->mId, "Misc_SoulGem_Azura")) mSoulGemPtr.getCellRef().mSoul=""; else mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); From 71b4319a0ce170b9815c480ee5e5a1cb2b1f0d6f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:31:38 +0200 Subject: [PATCH 0892/1483] Yet another change in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4852efb810..a9c47aa4e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev libboost-program-options-dev libboost-system-dev libboost-wave-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-dev libqt4-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From a9b56eedc3c220a108915d3caf9234a60129c99e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 18:51:40 +0200 Subject: [PATCH 0893/1483] Support NIF "glow maps", which are basically an emissive channel. --- components/nif/property.hpp | 4 ++-- components/nifogre/ogrenifloader.cpp | 7 ++++++ files/materials/objects.mat | 14 ++++++++++++ files/materials/objects.shader | 33 ++++++++++++++++++++++++---- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 00cdc0e008..fd96ad0481 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -64,7 +64,7 @@ public: bool inUse; NiSourceTexturePtr texture; - int clamp, set, filter; + int clamp, uvSet, filter; short unknown2; void read(NIFStream *nif) @@ -75,7 +75,7 @@ public: texture.read(nif); clamp = nif->getInt(); filter = nif->getInt(); - set = nif->getInt(); + uvSet = nif->getInt(); // I have no idea, but I think these are actually two // PS2-specific shorts (ps2L and ps2K), followed by an unknown diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index c5dc7fbb98..f8eca821ff 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -749,6 +749,13 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); + if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) + { + instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); + } + for(int i = 1;i < 7;i++) { if(!texName[i].empty()) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 00b43a9d0d..8740c82c34 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -7,6 +7,9 @@ material openmw_objects_base vertmode 0 diffuseMap black.png normalMap + emissiveMap + use_emissive_map false + emissiveMapUVSet 0 is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default @@ -24,6 +27,8 @@ material openmw_objects_base vertexcolor_mode $vertmode is_transparent $is_transparent normalMap $normalMap + emissiveMapUVSet $emissiveMapUVSet + emissiveMap $emissiveMap } diffuse $diffuse @@ -39,12 +44,21 @@ material openmw_objects_base { direct_texture $diffuseMap create_in_ffp true + tex_coord_set $emissiveMapUVSet } texture_unit normalMap { direct_texture $normalMap } + + texture_unit emissiveMap + { + create_in_ffp $use_emissive_map + colour_op add + direct_texture $emissiveMap + tex_coord_set $emissiveMapUVSet + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 73968a6b3e..d0e8173733 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -15,6 +15,10 @@ #endif #define NORMAL_MAP @shPropertyHasValue(normalMap) +#define EMISSIVE_MAP @shPropertyHasValue(emissiveMap) + +// right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more +#define SECOND_UV_SET @shPropertyString(emissiveMapUVSet) // if normal mapping is enabled, we force pixel lighting #define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) @@ -42,7 +46,11 @@ #endif shVertexInput(float2, uv0) - shOutput(float2, UV) +#if SECOND_UV_SET + shVertexInput(float2, uv1) +#endif + shOutput(float4, UV) + shNormalInput(float4) #if NORMAL_MAP @@ -109,7 +117,12 @@ SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV = uv0; + + UV.xy = uv0; +#if SECOND_UV_SET + UV.zw = uv1; +#endif + #if NORMAL_MAP tangentPassthrough = tangent.xyz; #endif @@ -219,7 +232,11 @@ shSampler2D(normalMap) #endif - shInput(float2, UV) +#if EMISSIVE_MAP + shSampler2D(emissiveMap) +#endif + + shInput(float4, UV) #if NORMAL_MAP shInput(float3, tangentPassthrough) @@ -294,7 +311,7 @@ SH_START_PROGRAM { - shOutputColour(0) = shSample(diffuseMap, UV); + shOutputColour(0) = shSample(diffuseMap, UV.xy); #if NORMAL_MAP float3 normal = normalPassthrough; @@ -399,6 +416,14 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); #endif +#endif + +#if EMISSIVE_MAP + #if SECOND_UV_SET + shOutputColour(0).xyz += shSample(emissiveMap, UV.zw).xyz; + #else + shOutputColour(0).xyz += shSample(emissiveMap, UV.xy).xyz; + #endif #endif // prevent negative colour output (for example with negative lights) From 2a5fc7cd822e9a204b63bfdf858cec1c7eefba53 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:02:21 +0200 Subject: [PATCH 0894/1483] Change in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a9c47aa4e2..4d1257d2bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev libboost-program-options-dev libboost-system-dev libboost-wave-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-dev libqt4-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev -script: make + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev 0ibpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev +script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: - master From f655b9997cc4e04f606f726452ad241eabe57c5c Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:10:57 +0200 Subject: [PATCH 0895/1483] Added printing CMakeCache.txt file For debug purposes, should be removed if compilation succeed. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4d1257d2bf..d99809590e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ before_script: - mkdir build - cd build - cmake .. -DMYGUI_STATIC=1 + - cat CMakeCache.txt before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps From d070860f0943c2fa5ac22762128554b5fcf623be Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:14:13 +0200 Subject: [PATCH 0896/1483] Fixed typo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d99809590e..7f361f5d40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev 0ibpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: From af509ce016ee85094fcd75f69eadf29109c2757f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:19:25 +0200 Subject: [PATCH 0897/1483] Restored building with static ogre. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7f361f5d40..db0a47d844 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DMYGUI_STATIC=1 + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 - cat CMakeCache.txt before_install: - git submodule update --init --recursive From 8ca88d1a708b05741240eb1e1b04d63449f2f2ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 21:13:01 +0200 Subject: [PATCH 0898/1483] Fix merchant repair menu allowing repair of repair items --- apps/openmw/mwgui/merchantrepair.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 0a65326050..1c9056748b 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -40,7 +40,8 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); - for (MWWorld::ContainerStoreIterator iter (store.begin()); + int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; + for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); iter!=store.end(); ++iter) { if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) From 43cdbd033d690dd904bf6f98dd39423f3182443f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 21:14:49 +0200 Subject: [PATCH 0899/1483] Display remaining item health / enchantment charge in HUD icons, display remaining enchanment charge in tooltips --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwclass/armor.cpp | 2 ++ apps/openmw/mwclass/clothing.cpp | 2 ++ apps/openmw/mwclass/weapon.cpp | 3 +++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 4 ++-- apps/openmw/mwgui/tooltips.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 9 +++++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++-- 11 files changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b271aed182..976d7d84c1 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -182,8 +182,8 @@ namespace MWBase virtual void activateQuickKey (int index) = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; - virtual void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) = 0; - virtual void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) = 0; + virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0; + virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0; virtual void unsetSelectedSpell() = 0; virtual void unsetSelectedWeapon() = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index b94c270d56..320944d3ce 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -260,6 +260,8 @@ namespace MWClass } info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; info.text = text; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index d65376898e..abad267675 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -207,6 +207,8 @@ namespace MWClass } info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; info.text = text; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index ed2a095e37..0a527262f8 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -349,6 +349,9 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index aeab5f94aa..001f42bd11 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -294,7 +294,7 @@ namespace MWGui if (weaponSlot == invStore.end()) mWindowManager.unsetSelectedWeapon(); else - mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability + mWindowManager.setSelectedWeapon(*weaponSlot); /// \todo track weapon durability mPreviewDirty = true; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 5ea13fb0d7..2e4bf9100b 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -346,7 +346,7 @@ namespace MWGui store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item, 100); /// \todo track charge % + mWindowManager.setSelectedEnchantItem(item); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d7fb0e1bcd..021a849a08 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -382,7 +382,7 @@ namespace MWGui store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item, 100); /// \todo track charge % + mWindowManager.setSelectedEnchantItem(item); updateSpells(); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index af3e146bba..9292e60e5c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -456,8 +456,8 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) if (enchant->mData.mType == ESM::Enchantment::WhenStrikes || enchant->mData.mType == ESM::Enchantment::WhenUsed) { - /// \todo store the current enchantment charge somewhere - int charge = enchant->mData.mCharge; + int maxCharge = enchant->mData.mCharge; + int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; const int chargeWidth = 204; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index ba94915cc7..da5a35221c 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -17,6 +17,7 @@ namespace MWGui : isPotion(false) , imageSize(32) , wordWrap(true) + , remainingEnchantCharge(-1) {} std::string caption; @@ -26,6 +27,7 @@ namespace MWGui // enchantment (for cloth, armor, weapons) std::string enchant; + int remainingEnchantCharge; // effects (for potions, ingredients) Widgets::SpellEffectList effects; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c975b2cdba..f994683a66 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -933,14 +933,19 @@ void WindowManager::setSelectedSpell(const std::string& spellId, int successChan mSpellWindow->setTitle(spell->mName); } -void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) +void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() + .find(MWWorld::Class::get(item).getEnchantment(item)); + + int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); } -void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) +void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { + int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c14c6b2fe4..3c9fc586a3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -179,8 +179,8 @@ namespace MWGui virtual void activateQuickKey (int index); virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); - virtual void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); - virtual void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); + virtual void setSelectedEnchantItem(const MWWorld::Ptr& item); + virtual void setSelectedWeapon(const MWWorld::Ptr& item); virtual void unsetSelectedSpell(); virtual void unsetSelectedWeapon(); From ebaf80d53921e51aa9b3c8cd823ef191b2490d9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 23:55:57 +0200 Subject: [PATCH 0900/1483] Trace actors onto the ground after load, when moved to a different cell by the console or on player cell change. --- apps/openmw/mwbase/world.hpp | 3 ++ apps/openmw/mwclass/creature.cpp | 6 +++ apps/openmw/mwclass/creature.hpp | 2 + apps/openmw/mwclass/npc.cpp | 5 ++ apps/openmw/mwclass/npc.hpp | 2 + apps/openmw/mwrender/renderingmanager.cpp | 27 +++++----- apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwrender/terrain.cpp | 11 ++++ apps/openmw/mwrender/terrain.hpp | 3 ++ .../mwscript/transformationextensions.cpp | 3 ++ apps/openmw/mwworld/class.cpp | 4 ++ apps/openmw/mwworld/class.hpp | 3 ++ apps/openmw/mwworld/physicssystem.cpp | 50 ++++++++++++++++++- apps/openmw/mwworld/physicssystem.hpp | 1 + apps/openmw/mwworld/scene.cpp | 6 ++- apps/openmw/mwworld/worldimp.cpp | 19 +++++++ apps/openmw/mwworld/worldimp.hpp | 3 ++ libs/openengine/bullet/physic.cpp | 3 +- 18 files changed, 138 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 8eea383eb4..040dc703c0 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -216,6 +216,9 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0; + ///< Adjust position after load to be on ground. Must be called after model load. + virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1097f8f29c..04889360f3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -9,6 +9,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" @@ -86,6 +87,11 @@ namespace MWClass return ref->mBase->mId; } + void Creature::adjustPosition(const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr); + } + void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { MWRender::Actors& actors = renderingInterface.getActors(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index ea356165eb..297c2ea61b 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -22,6 +22,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cd6b0def11..7cda87bb15 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -160,6 +160,11 @@ namespace MWClass return ref->mBase->mId; } + void Npc::adjustPosition(const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr); + } + void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 1a10bce6c1..d1a9158fdf 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -44,6 +44,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7c442c6868..2f49a40316 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -529,25 +529,28 @@ void RenderingManager::applyFog (bool underwater) void RenderingManager::setAmbientMode() { - switch (mAmbientMode) - { + switch (mAmbientMode) + { case 0: - - setAmbientColour(mAmbientColor); - break; + setAmbientColour(mAmbientColor); + break; case 1: - - setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); - break; + setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); + break; case 2: - - setAmbientColour(ColourValue(1,1,1)); - break; - } + setAmbientColour(ColourValue(1,1,1)); + break; + } } +float RenderingManager::getTerrainHeightAt(Ogre::Vector3 worldPos) +{ + return mTerrainManager->getTerrainHeightAt(worldPos); +} + + void RenderingManager::configureAmbient(MWWorld::Ptr::CellStore &mCell) { mAmbientColor.setAsABGR (mCell.mCell->mAmbi.mAmbient); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index fd43438ca5..b343a60bdb 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -158,6 +158,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); + float getTerrainHeightAt (Ogre::Vector3 worldPos); + void setGlare(bool glare); void skyEnable (); void skyDisable (); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 438366873c..c27dce6cad 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -71,6 +71,17 @@ namespace MWRender //---------------------------------------------------------------------------------------------- + float TerrainManager::getTerrainHeightAt(Vector3 worldPos) + { + Ogre::Terrain* terrain = NULL; + float height = mTerrainGroup.getHeightAtWorldPosition(worldPos, &terrain); + if (terrain == NULL) + return std::numeric_limits().min(); + return height; + } + + //---------------------------------------------------------------------------------------------- + TerrainManager::~TerrainManager() { OGRE_DELETE mTerrainGlobals; diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index 484a0dbe3a..45c56390e8 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -40,6 +40,9 @@ namespace MWRender{ void cellAdded(MWWorld::CellStore* store); void cellRemoved(MWWorld::CellStore* store); + + float getTerrainHeightAt (Ogre::Vector3 worldPos); + private: Ogre::TerrainGlobalOptions* mTerrainGlobals; Ogre::TerrainGroup mTerrainGroup; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index d86a6e3486..000cc545db 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -303,6 +303,8 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + + MWBase::Environment::get().getWorld()->adjustPosition(ptr); } else { @@ -341,6 +343,7 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + MWBase::Environment::get().getWorld()->adjustPosition(ptr); } }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 98579797c7..2dfa241b3b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,6 +259,10 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } + void Class::adjustPosition(const MWWorld::Ptr& ptr) const + { + } + MWWorld::Ptr Class::copyToCellImpl(const Ptr &ptr, CellStore &cell) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e34ebdde77..de4741e38b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -81,6 +81,9 @@ namespace MWWorld ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + ///< Adjust position to stand on ground. Must be called post model load + virtual MWMechanics::CreatureStats& getCreatureStats (const Ptr& ptr) const; ///< Return creature stats or throw an exception, if class does not have creature stats /// (default implementation: throw an exceoption) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 28f3317065..19ee2e517b 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -88,6 +88,50 @@ namespace MWWorld } public: + static Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, OEngine::Physic::PhysicEngine *engine) + { + const ESM::Position &refpos = ptr.getRefData().getPosition(); + Ogre::Vector3 position(refpos.pos); + + bool hit=false; + bool isInterior = !ptr.getCell()->isExterior(); + + OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); + if (!physicActor) + return position; + + bool wasCollisionMode = physicActor->getCollisionMode(); + + physicActor->enableCollisions(false); + + Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); + + Ogre::Vector3 newPosition = position; + + traceResults trace; //no initialization needed + + int maxHeight = 400.f; + int steps = 100; + for (int i=0; isetOnGround(hit); + physicActor->enableCollisions(wasCollisionMode); + + if (hit) + return newPosition; + else + return position; + } + + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { @@ -318,7 +362,7 @@ namespace MWWorld btVector3 btTo = btVector3(to.x, to.y, to.z); std::pair test = mEngine->rayTest(btFrom, btTo); - if (test.first == "") { + if (test.second == -1) { return std::make_pair(false, Ogre::Vector3()); } return std::make_pair(true, ray.getPoint(len * test.second)); @@ -351,6 +395,10 @@ namespace MWWorld return MovementSolver::move(ptr, movement, time, gravity, mEngine); } + Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr) + { + return MovementSolver::traceDown(ptr, mEngine); + } void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 2e48be4079..4eec9367cb 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -51,6 +51,7 @@ namespace MWWorld bool toggleCollisionMode(); Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); + Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 339026ca60..c8853f4842 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -51,6 +51,7 @@ namespace class_.insertObject(ptr, physics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); + class_.adjustPosition(ptr); } catch (const std::exception& e) { @@ -99,7 +100,6 @@ namespace MWWorld } mRendering.removeCell(*iter); - //mPhysics->removeObject("Unnamed_43"); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); MWBase::Environment::get().getMechanicsManager()->drop (*iter); @@ -165,6 +165,8 @@ namespace MWWorld float y = Ogre::Radian(pos.rot[1]).valueDegrees(); float z = Ogre::Radian(pos.rot[2]).valueDegrees(); world->rotateObject(player, x, y, z); + + world->adjustPosition(player); } MWBase::MechanicsManager *mechMgr = @@ -355,6 +357,8 @@ namespace MWWorld float y = Ogre::Radian(position.rot[1]).valueDegrees(); float z = Ogre::Radian(position.rot[2]).valueDegrees(); world->rotateObject(world->getPlayer().getPlayer(), x, y, z); + + world->adjustPosition(world->getPlayer().getPlayer()); return; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ae0e02c8c9..2ce753b816 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -709,6 +709,7 @@ namespace MWWorld pos.pos[0] = x; pos.pos[1] = y; pos.pos[2] = z; + Ogre::Vector3 vec(x, y, z); CellStore *currCell = ptr.getCell(); @@ -822,6 +823,24 @@ namespace MWWorld } } + void World::adjustPosition(const Ptr &ptr) + { + Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); + + if (!isFlying(ptr)) + { + Ogre::Vector3 traced = mPhysics->traceDown(ptr); + if (traced.z < pos.z) + pos.z = traced.z; + } + + float terrainHeight = mRendering->getTerrainHeightAt(pos); + if (pos.z < terrainHeight) + pos.z = terrainHeight; + + moveObject(ptr, pos.x, pos.y, pos.z); + } + void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) { rotateObjectImp(ptr, Ogre::Vector3(Ogre::Degree(x).valueRadians(), diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8cff50bd16..5ae87a1ff7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -188,6 +188,9 @@ namespace MWWorld virtual Ptr searchPtrViaHandle (const std::string& handle); ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found + virtual void adjustPosition (const Ptr& ptr); + ///< Adjust position after load to be on ground. Must be called after model load. + virtual void enable (const Ptr& ptr); virtual void disable (const Ptr& ptr); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7b831d32c5..f71fa4320b 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -323,7 +323,8 @@ namespace Physic mHeightFieldMap [name] = hf; - dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); + dynamicsWorld->addRigidBody(body,CollisionType_World|CollisionType_Raycasting, + CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal|CollisionType_Raycasting); } void PhysicEngine::removeHeightField(int x, int y) From fea44c05d4a337ffe4f5543c94c2a9ec3ab724bc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:10:26 +0200 Subject: [PATCH 0901/1483] added class record verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/classcheck.cpp | 63 ++++++++++++++++++++++++++ apps/opencs/model/tools/classcheck.hpp | 29 ++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ apps/opencs/model/world/data.cpp | 10 ++++ apps/opencs/model/world/data.hpp | 4 ++ 6 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/classcheck.cpp create mode 100644 apps/opencs/model/tools/classcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index a305d90d93..adfc5f4aeb 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck + stage verifier mandatoryid skillcheck classcheck ) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp new file mode 100644 index 0000000000..302af6b9db --- /dev/null +++ b/apps/opencs/model/tools/classcheck.cpp @@ -0,0 +1,63 @@ + +#include "classcheck.hpp" + +#include +#include + +#include +#include + +#include "../world/universalid.hpp" + +CSMTools::ClassCheckStage::ClassCheckStage (const CSMWorld::IdCollection& classes) +: mClasses (classes) +{} + +int CSMTools::ClassCheckStage::setup() +{ + return mClasses.getSize(); +} + +void CSMTools::ClassCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Class& class_= mClasses.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId); + + // test for empty name and description + if (class_.mName.empty()) + messages.push_back (id.toString() + "|" + class_.mId + " has an empty name"); + + if (class_.mDescription.empty()) + messages.push_back (id.toString() + "|" + class_.mId + " has an empty description"); + + // test for invalid attributes + for (int i=0; i<2; ++i) + if (class_.mData.mAttribute[i]==-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Attribute #" << i << " of " << class_.mId << " is not set"; + + messages.push_back (stream.str()); + } + + // test for non-unique skill + std::map skills; // ID, number of occurrences + + for (int i=0; i<5; ++i) + for (int i2=0; i2<2; ++i2) + ++skills[class_.mData.mSkills[i][i2]]; + + for (std::map::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) + if (iter->second>1) + { + std::ostringstream stream; + + stream + << id.toString() << "|" + << ESM::Skill::indexToId (iter->first) << " is listed more than once"; + + messages.push_back (stream.str()); + } +} \ No newline at end of file diff --git a/apps/opencs/model/tools/classcheck.hpp b/apps/opencs/model/tools/classcheck.hpp new file mode 100644 index 0000000000..a29d7c8b78 --- /dev/null +++ b/apps/opencs/model/tools/classcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_CLASSCHECK_H +#define CSM_TOOLS_CLASSCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that class records are internally consistent + class ClassCheckStage : public Stage + { + const CSMWorld::IdCollection& mClasses; + + public: + + ClassCheckStage (const CSMWorld::IdCollection& classes); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 33cc3cc61b..84a6910ecc 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -13,6 +13,7 @@ #include "reportmodel.hpp" #include "mandatoryid.hpp" #include "skillcheck.hpp" +#include "classcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -54,6 +55,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); + + mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); } return mVerifier; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 13fff7f096..fc6cc01220 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -107,6 +107,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSkills() return mSkills; } +const CSMWorld::IdCollection& CSMWorld::Data::getClasses() const +{ + return mClasses; +} + +CSMWorld::IdCollection& CSMWorld::Data::getClasses() +{ + return mClasses; +} + const CSMWorld::IdCollection& CSMWorld::Data::getFactions() const { return mFactions; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 1e2894774a..16a9685a53 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -54,6 +54,10 @@ namespace CSMWorld IdCollection& getSkills(); + const IdCollection& getClasses() const; + + IdCollection& getClasses(); + const IdCollection& getFactions() const; IdCollection& getFactions(); From 06533b8d71a10139816996a3f68042b7f4aff14e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:31:10 +0200 Subject: [PATCH 0902/1483] additional check for using the same attribute twice in a class --- apps/opencs/model/tools/classcheck.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 302af6b9db..da2e9f19a6 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -42,6 +42,15 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector& me messages.push_back (stream.str()); } + if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Class lists same attribute twice"; + + messages.push_back (stream.str()); + } + // test for non-unique skill std::map skills; // ID, number of occurrences From b5eaa464ad8cb840437a9280f278f25813e18930 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:39:43 +0200 Subject: [PATCH 0903/1483] added faction record verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/factioncheck.cpp | 61 ++++++++++++++++++++++++ apps/opencs/model/tools/factioncheck.hpp | 29 +++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/factioncheck.cpp create mode 100644 apps/opencs/model/tools/factioncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index adfc5f4aeb..07766507f7 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck + stage verifier mandatoryid skillcheck classcheck factioncheck ) diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp new file mode 100644 index 0000000000..ea4a87eec8 --- /dev/null +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -0,0 +1,61 @@ + +#include "factioncheck.hpp" + +#include +#include + +#include +#include + +#include "../world/universalid.hpp" + +CSMTools::FactionCheckStage::FactionCheckStage (const CSMWorld::IdCollection& factions) +: mFactions (factions) +{} + +int CSMTools::FactionCheckStage::setup() +{ + return mFactions.getSize(); +} + +void CSMTools::FactionCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Faction& faction = mFactions.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Faction, faction.mId); + + // test for empty name + if (faction.mName.empty()) + messages.push_back (id.toString() + "|" + faction.mId + " has an empty name"); + + // test for invalid attributes + if (faction.mData.mAttributes[0]==faction.mData.mAttributes[1] && faction.mData.mAttributes[0]!=-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Faction lists same attribute twice"; + + messages.push_back (stream.str()); + } + + // test for non-unique skill + std::map skills; // ID, number of occurrences + + for (int i=0; i<6; ++i) + if (faction.mData.mSkills[i]!=-1) + ++skills[faction.mData.mSkills[i]]; + + for (std::map::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) + if (iter->second>1) + { + std::ostringstream stream; + + stream + << id.toString() << "|" + << ESM::Skill::indexToId (iter->first) << " is listed more than once"; + + messages.push_back (stream.str()); + } + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/factioncheck.hpp b/apps/opencs/model/tools/factioncheck.hpp new file mode 100644 index 0000000000..8686505727 --- /dev/null +++ b/apps/opencs/model/tools/factioncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_FACTIONCHECK_H +#define CSM_TOOLS_FACTIONCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that faction records are internally consistent + class FactionCheckStage : public Stage + { + const CSMWorld::IdCollection& mFactions; + + public: + + FactionCheckStage (const CSMWorld::IdCollection& factions); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 84a6910ecc..db45de43e5 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -14,6 +14,7 @@ #include "mandatoryid.hpp" #include "skillcheck.hpp" #include "classcheck.hpp" +#include "factioncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -57,6 +58,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); + + mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); } return mVerifier; From 7136ac0079ed293752202416e6a1f1c9478f0a90 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:58:53 +0200 Subject: [PATCH 0904/1483] added missing attribute columns to faction table --- apps/esmtool/record.cpp | 8 ++++---- apps/opencs/model/tools/factioncheck.cpp | 2 +- apps/opencs/model/world/data.cpp | 2 ++ apps/openmw/mwdialogue/filter.cpp | 4 ++-- apps/openmw/mwgui/stats_window.cpp | 4 ++-- components/esm/loadfact.cpp | 2 +- components/esm/loadfact.hpp | 2 +- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 8f77e4b445..d15e7f2b0b 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -679,10 +679,10 @@ void Record::print() std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl; if (mData.mData.mUnknown != -1) std::cout << " Unknown: " << mData.mData.mUnknown << std::endl; - std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttributes[0]) - << " (" << mData.mData.mAttributes[0] << ")" << std::endl; - std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttributes[1]) - << " (" << mData.mData.mAttributes[1] << ")" << std::endl; + std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute[0]) + << " (" << mData.mData.mAttribute[0] << ")" << std::endl; + std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1]) + << " (" << mData.mData.mAttribute[1] << ")" << std::endl; for (int i = 0; i != 6; i++) if (mData.mData.mSkills[i] != -1) std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index ea4a87eec8..af26904efa 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -29,7 +29,7 @@ void CSMTools::FactionCheckStage::perform (int stage, std::vector& messages.push_back (id.toString() + "|" + faction.mId + " has an empty name"); // test for invalid attributes - if (faction.mData.mAttributes[0]==faction.mData.mAttributes[1] && faction.mData.mAttributes[0]!=-1) + if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) { std::ostringstream stream; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fc6cc01220..d62fd7267b 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -60,6 +60,8 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + mFactions.addColumn (new AttributesColumn (0)); + mFactions.addColumn (new AttributesColumn (1)); mFactions.addColumn (new HiddenColumn); for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index ddb15d423d..78969ffd0b 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -569,8 +569,8 @@ bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& ac MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor); - return stats.getAttribute (faction.mData.mAttributes[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && - stats.getAttribute (faction.mData.mAttributes[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; + return stats.getAttribute (faction.mData.mAttribute[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && + stats.getAttribute (faction.mData.mAttribute[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; } bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 86019fa28d..0678e98919 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -500,8 +500,8 @@ void StatsWindow::updateSkillArea() text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttributes[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttributes[1]); + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); assert(attr1 && attr2); text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 12a76f1ade..e2712d462d 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -71,7 +71,7 @@ void Faction::save(ESMWriter &esm) void Faction::blank() { mName.clear(); - mData.mAttributes[0] = mData.mAttributes[1] = 0; + mData.mAttribute[0] = mData.mAttribute[1] = 0; mData.mUnknown = -1; mData.mIsHidden = 0; diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index edc4640bb1..891b996473 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -34,7 +34,7 @@ struct Faction struct FADTstruct { // Which attributes we like - int mAttributes[2]; + int mAttribute[2]; RankData mRankData[10]; From e8c32d0c3db7a77ed27db957e5b1d718bb2fd961 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 11:23:17 +0200 Subject: [PATCH 0905/1483] MWWorld::Player cleanup --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwscript/controlextensions.cpp | 1 + apps/openmw/mwworld/cellstore.hpp | 35 +---------------- apps/openmw/mwworld/livecellref.hpp | 45 ++++++++++++++++++++++ apps/openmw/mwworld/player.cpp | 31 +++++++++++++-- apps/openmw/mwworld/player.hpp | 33 ++++++---------- 6 files changed, 88 insertions(+), 59 deletions(-) create mode 100644 apps/openmw/mwworld/livecellref.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index beb0b9aadf..8a0030be42 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem + esmstore store recordcmp fallback actionrepair actionsoulgem livecellref ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 8d65dfdd5b..ac53b8ee25 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -12,6 +12,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/ptr.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2e6b45bb7e..0cc111cde3 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -6,45 +6,12 @@ #include #include -#include "refdata.hpp" +#include "livecellref.hpp" #include "esmstore.hpp" struct C; namespace MWWorld { - class Ptr; - class ESMStore; - - /// A reference to one object (of any type) in a cell. - /// - /// Constructing this with a CellRef instance in the constructor means that - /// in practice (where D is RefData) the possibly mutable data is copied - /// across to mData. If later adding data (such as position) to CellRef - /// this would have to be manually copied across. - template - struct LiveCellRef - { - LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) - : mBase(b), mRef(cref), mData(mRef) - {} - - LiveCellRef(const X* b = NULL) - : mBase(b), mData(mRef) - {} - - // The object that this instance is based on. - const X* mBase; - - /* Information about this instance, such as 3D location and - rotation and individual type-dependent data. - */ - ESM::CellRef mRef; - - /// runtime-data - RefData mData; - }; - - template bool operator==(const LiveCellRef& ref, int pRefnum); /// A list of cell references template diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp new file mode 100644 index 0000000000..4c5efb861f --- /dev/null +++ b/apps/openmw/mwworld/livecellref.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_MWWORLD_LIVECELLREF_H +#define GAME_MWWORLD_LIVECELLREF_H + +#include + +#include "refdata.hpp" + +namespace MWWorld +{ + class Ptr; + class ESMStore; + + /// A reference to one object (of any type) in a cell. + /// + /// Constructing this with a CellRef instance in the constructor means that + /// in practice (where D is RefData) the possibly mutable data is copied + /// across to mData. If later adding data (such as position) to CellRef + /// this would have to be manually copied across. + template + struct LiveCellRef + { + LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) + : mBase(b), mRef(cref), mData(mRef) + {} + + LiveCellRef(const X* b = NULL) + : mBase(b), mData(mRef) + {} + + // The object that this instance is based on. + const X* mBase; + + /* Information about this instance, such as 3D location and + rotation and individual type-dependent data. + */ + ESM::CellRef mRef; + + /// runtime-data + RefData mData; + }; + + template bool operator==(const LiveCellRef& ref, int pRefnum); +} + +#endif diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index ea8a02dee9..3338f08edf 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,14 +1,13 @@ #include "player.hpp" - #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" + +#include "../mwworld/ptr.hpp" #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" -#include "esmstore.hpp" #include "class.hpp" namespace MWWorld @@ -25,12 +24,38 @@ namespace MWWorld playerPos[0] = playerPos[1] = playerPos[2] = 0; } + void Player::setCell (MWWorld::CellStore *cellStore) + { + mCellStore = cellStore; + } + + MWWorld::Ptr Player::getPlayer() + { + MWWorld::Ptr ptr (&mPlayer, mCellStore); + return ptr; + } + + void Player::setBirthSign (const std::string &sign) + { + mSign = sign; + } + + const std::string& Player::getBirthSign() const + { + return mSign; + } + void Player::setDrawState (MWMechanics::DrawState_ state) { MWWorld::Ptr ptr = getPlayer(); MWWorld::Class::get(ptr).getNpcStats(ptr).setDrawState (state); } + bool Player::getAutoMove() const + { + return mAutoMove; + } + void Player::setAutoMove (bool enable) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index c985510917..dfaddf66a9 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -1,15 +1,20 @@ #ifndef GAME_MWWORLD_PLAYER_H #define GAME_MWWORLD_PLAYER_H -#include "../mwworld/cellstore.hpp" #include "../mwworld/refdata.hpp" -#include "../mwworld/ptr.hpp" +#include "../mwworld/livecellref.hpp" #include "../mwmechanics/drawstate.hpp" +namespace ESM +{ + struct NPC; +} + namespace MWBase { class World; + class Ptr; } namespace MWWorld @@ -30,31 +35,17 @@ namespace MWWorld Player(const ESM::NPC *player, const MWBase::World& world); - void setCell (MWWorld::CellStore *cellStore) - { - mCellStore = cellStore; - } + void setCell (MWWorld::CellStore *cellStore); - MWWorld::Ptr getPlayer() - { - MWWorld::Ptr ptr (&mPlayer, mCellStore); - return ptr; - } + MWWorld::Ptr getPlayer(); - void setBirthSign(const std::string &sign) { - mSign = sign; - } + void setBirthSign(const std::string &sign); - const std::string &getBirthSign() const { - return mSign; - } + const std::string &getBirthSign() const; void setDrawState (MWMechanics::DrawState_ state); - bool getAutoMove() const - { - return mAutoMove; - } + bool getAutoMove() const; MWMechanics::DrawState_ getDrawState(); /// \todo constness From 8c7d578ddcf9a8d91e80c98618a19045252d1959 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:13:15 +0200 Subject: [PATCH 0906/1483] moved the CellRef struct to its own header --- apps/openmw/mwworld/livecellref.hpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/cellref.hpp | 90 +++++++++++++++++++++++++++++ components/esm/loadcell.hpp | 78 +------------------------ 4 files changed, 93 insertions(+), 79 deletions(-) create mode 100644 components/esm/cellref.hpp diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 4c5efb861f..8f419b626f 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWWORLD_LIVECELLREF_H #define GAME_MWWORLD_LIVECELLREF_H -#include +#include #include "refdata.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 88bf764445..a2f416fcca 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (esm loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat - loadweap records aipackage effectlist spelllist variant variantimp loadtes3 + loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref ) add_component_dir (misc diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp new file mode 100644 index 0000000000..fb03a90844 --- /dev/null +++ b/components/esm/cellref.hpp @@ -0,0 +1,90 @@ +#ifndef OPENMW_ESM_CELLREF_H +#define OPENMW_ESM_CELLREF_H + +#include + +#include "defs.hpp" + +namespace ESM +{ + class ESMWriter; + + /* Cell reference. This represents ONE object (of many) inside the + cell. The cell references are not loaded as part of the normal + loading process, but are rather loaded later on demand when we are + setting up a specific cell. + */ + + class CellRef + { + public: + + int mRefnum; // Reference number + std::string mRefID; // ID of object being referenced + + float mScale; // Scale applied to mesh + + // The NPC that owns this object (and will get angry if you steal + // it) + std::string mOwner; + + // I have no idea, looks like a link to a global variable? + std::string mGlob; + + // ID of creature trapped in this soul gem (?) + std::string mSoul; + + // ?? CNAM has a faction name, might be for objects/beds etc + // belonging to a faction. + std::string mFaction; + + // INDX might be PC faction rank required to use the item? Sometimes + // is -1, which I assume means "any rank". + int mFactIndex; + + // For weapon or armor, this is the remaining item health. + // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + int mCharge; + + // Remaining enchantment charge + float mEnchantmentCharge; + + // This is 5 for Gold_005 references, 100 for Gold_100 and so on. + int mGoldValue; + + // For doors - true if this door teleports to somewhere else, false + // if it should open through animation. + bool mTeleport; + + // Teleport location for the door, if this is a teleporting door. + Position mDoorDest; + + // Destination cell for doors (optional) + std::string mDestCell; + + // Lock level for doors and containers + int mLockLevel; + std::string mKey, mTrap; // Key and trap ID names, if any + + // This corresponds to the "Reference Blocked" checkbox in the construction set, + // which prevents editing that reference. + // -1 is not blocked, otherwise it is blocked. + signed char mReferenceBlocked; + + // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. + int mDeleted; + + // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza + // Brindisi Dorom", where it has the value 100. Also only for + // activators. + int mFltv; + int mNam0; + + // Position and rotation of this object within the cell + Position mPos; + + void save(ESMWriter &esm); + }; +} + +#endif \ No newline at end of file diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index afc953f54c..44412b5eb9 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -7,95 +7,19 @@ #include "esmcommon.hpp" #include "defs.hpp" - +#include "cellref.hpp" namespace MWWorld { class ESMStore; } - namespace ESM { class ESMReader; class ESMWriter; -/* Cell reference. This represents ONE object (of many) inside the - cell. The cell references are not loaded as part of the normal - loading process, but are rather loaded later on demand when we are - setting up a specific cell. - */ -class CellRef -{ -public: - int mRefnum; // Reference number - std::string mRefID; // ID of object being referenced - - float mScale; // Scale applied to mesh - - // The NPC that owns this object (and will get angry if you steal - // it) - std::string mOwner; - - // I have no idea, looks like a link to a global variable? - std::string mGlob; - - // ID of creature trapped in this soul gem (?) - std::string mSoul; - - // ?? CNAM has a faction name, might be for objects/beds etc - // belonging to a faction. - std::string mFaction; - - // INDX might be PC faction rank required to use the item? Sometimes - // is -1, which I assume means "any rank". - int mFactIndex; - - // For weapon or armor, this is the remaining item health. - // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - int mCharge; - - // Remaining enchantment charge - float mEnchantmentCharge; - - // This is 5 for Gold_005 references, 100 for Gold_100 and so on. - int mGoldValue; - - // For doors - true if this door teleports to somewhere else, false - // if it should open through animation. - bool mTeleport; - - // Teleport location for the door, if this is a teleporting door. - Position mDoorDest; - - // Destination cell for doors (optional) - std::string mDestCell; - - // Lock level for doors and containers - int mLockLevel; - std::string mKey, mTrap; // Key and trap ID names, if any - - // This corresponds to the "Reference Blocked" checkbox in the construction set, - // which prevents editing that reference. - // -1 is not blocked, otherwise it is blocked. - signed char mReferenceBlocked; - - // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. - int mDeleted; - - // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza - // Brindisi Dorom", where it has the value 100. Also only for - // activators. - int mFltv; - int mNam0; - - // Position and rotation of this object within the cell - Position mPos; - - void save(ESMWriter &esm); -}; - /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another plugin tries to move it independently. From 5244362fba72d6e47e54a75b9d6a5e890d8bb266 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:23:06 +0200 Subject: [PATCH 0907/1483] some cleanup --- apps/openmw/mwworld/cellstore.hpp | 1 - apps/openmw/mwworld/livecellref.hpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 0cc111cde3..7e4fc407d4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,7 +9,6 @@ #include "livecellref.hpp" #include "esmstore.hpp" -struct C; namespace MWWorld { diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 8f419b626f..28c1bb5c27 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -39,7 +39,7 @@ namespace MWWorld RefData mData; }; - template bool operator==(const LiveCellRef& ref, int pRefnum); +// template bool operator==(const LiveCellRef& ref, int pRefnum); } #endif From 111ebf84bb352072e60cc94e7e7427872b66aa91 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:27:57 +0200 Subject: [PATCH 0908/1483] replaced an include with a forward declaration --- apps/openmw/mwscript/locals.cpp | 13 ++++++++----- apps/openmw/mwscript/locals.hpp | 10 +++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 2cf2a97c1d..180a2791bc 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -1,8 +1,11 @@ #include "locals.hpp" +#include + +#include + #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" -#include namespace MWScript { @@ -39,9 +42,9 @@ namespace MWScript } return 0; } - + bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) - { + { Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -51,10 +54,10 @@ namespace MWScript { case 's': mShorts.at (index) = val; break; - + case 'l': mLongs.at (index) = val; break; - + case 'f': mFloats.at (index) = val; break; } diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index 1d9b9c3e4f..deae0d44ea 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -3,9 +3,13 @@ #include -#include #include +namespace ESM +{ + struct Script; +} + namespace MWScript { class Locals @@ -14,11 +18,11 @@ namespace MWScript std::vector mShorts; std::vector mLongs; std::vector mFloats; - + void configure (const ESM::Script& script); bool setVarByInt(const std::string& script, const std::string& var, int val); int getIntVar (const std::string& script, const std::string& var); ///< if var does not exist, returns 0 - + }; } From 62d70f17c859977ac631378595cdf09b18022258 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:42:38 +0200 Subject: [PATCH 0909/1483] removed another redundant include --- apps/openmw/mwworld/cellstore.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 7e4fc407d4..f8467c84f6 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWWORLD_CELLSTORE_H #define GAME_MWWORLD_CELLSTORE_H -#include - #include #include From 18e046e6285f41b588fba796da123a44faffeae0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 13:50:36 +0200 Subject: [PATCH 0910/1483] cleaned up race record struct --- apps/esmtool/record.cpp | 60 ++++++------------- .../mwmechanics/mechanicsmanagerimp.cpp | 16 +---- components/esm/loadrace.cpp | 9 +++ components/esm/loadrace.hpp | 13 ++-- 4 files changed, 34 insertions(+), 64 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index d15e7f2b0b..a6f77862ef 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1099,53 +1099,29 @@ void Record::print() template<> void Record::print() { + static const char *sAttributeNames[8] = + { + "Strength", "Intelligence", "Willpower", "Agility", + "Speed", "Endurance", "Personality", "Luck" + }; + std::cout << " Name: " << mData.mName << std::endl; std::cout << " Description: " << mData.mDescription << std::endl; std::cout << " Flags: " << raceFlags(mData.mData.mFlags) << std::endl; - std::cout << " Male:" << std::endl; - std::cout << " Strength: " - << mData.mData.mStrength.mMale << std::endl; - std::cout << " Intelligence: " - << mData.mData.mIntelligence.mMale << std::endl; - std::cout << " Willpower: " - << mData.mData.mWillpower.mMale << std::endl; - std::cout << " Agility: " - << mData.mData.mAgility.mMale << std::endl; - std::cout << " Speed: " - << mData.mData.mSpeed.mMale << std::endl; - std::cout << " Endurance: " - << mData.mData.mEndurance.mMale << std::endl; - std::cout << " Personality: " - << mData.mData.mPersonality.mMale << std::endl; - std::cout << " Luck: " - << mData.mData.mLuck.mMale << std::endl; - std::cout << " Height: " - << mData.mData.mHeight.mMale << std::endl; - std::cout << " Weight: " - << mData.mData.mWeight.mMale << std::endl; + for (int i=0; i<2; ++i) + { + bool male = i==0; - std::cout << " Female:" << std::endl; - std::cout << " Strength: " - << mData.mData.mStrength.mFemale << std::endl; - std::cout << " Intelligence: " - << mData.mData.mIntelligence.mFemale << std::endl; - std::cout << " Willpower: " - << mData.mData.mWillpower.mFemale << std::endl; - std::cout << " Agility: " - << mData.mData.mAgility.mFemale << std::endl; - std::cout << " Speed: " - << mData.mData.mSpeed.mFemale << std::endl; - std::cout << " Endurance: " - << mData.mData.mEndurance.mFemale << std::endl; - std::cout << " Personality: " - << mData.mData.mPersonality.mFemale << std::endl; - std::cout << " Luck: " - << mData.mData.mLuck.mFemale << std::endl; - std::cout << " Height: " - << mData.mData.mHeight.mFemale << std::endl; - std::cout << " Weight: " - << mData.mData.mWeight.mFemale << std::endl; + std::cout << (male ? " Male:" : " Female:") << std::endl; + + for (int i=0; i<8; ++i) + std::cout << " " << sAttributeNames[i] << ": " + << mData.mData.mAttributeValues[i].getValue (male) << std::endl; + + std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl; + std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl; + } for (int i = 0; i != 7; i++) // Not all races have 7 skills. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c8d8279210..8757213e99 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -53,21 +53,9 @@ namespace MWMechanics for (int i=0; i<8; ++i) { - const ESM::Race::MaleFemale *attribute = 0; - switch (i) - { - case 0: attribute = &race->mData.mStrength; break; - case 1: attribute = &race->mData.mIntelligence; break; - case 2: attribute = &race->mData.mWillpower; break; - case 3: attribute = &race->mData.mAgility; break; - case 4: attribute = &race->mData.mSpeed; break; - case 5: attribute = &race->mData.mEndurance; break; - case 6: attribute = &race->mData.mPersonality; break; - case 7: attribute = &race->mData.mLuck; break; - } + const ESM::Race::MaleFemale& attribute = race->mData.mAttributeValues[i]; - creatureStats.getAttribute(i).setBase ( - static_cast (male ? attribute->mMale : attribute->mFemale)); + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); } for (int i=0; i<27; ++i) diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 139ef081c0..94aa792bc6 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -5,6 +5,15 @@ namespace ESM { + int Race::MaleFemale::getValue (bool male) const + { + return male ? mMale : mFemale; + } + + int Race::MaleFemaleF::getValue (bool male) const + { + return male ? mMale : mFemale; + } void Race::load(ESMReader &esm) { diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 91a424c10b..845956686c 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -26,11 +26,15 @@ struct Race struct MaleFemale { int mMale, mFemale; + + int getValue (bool male) const; }; struct MaleFemaleF { float mMale, mFemale; + + int getValue (bool male) const; }; enum Flags @@ -45,14 +49,7 @@ struct Race SkillBonus mBonus[7]; // Attribute values for male/female - MaleFemale mStrength, - mIntelligence, - mWillpower, - mAgility, - mSpeed, - mEndurance, - mPersonality, - mLuck; + MaleFemale mAttributeValues[8]; // The actual eye level height (in game units) is (probably) given // as 'height' times 128. This has not been tested yet. From 97d617d43f0bb88d680ddab826ee158d6f73c5e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 04:33:56 -0700 Subject: [PATCH 0911/1483] Use more appropriate VBO settings Unskinned meshes don't need dynamic VBOs; they aren't rewritten since their transformations are handled by the modelview matrix. They also don't need the local RAM copy (the "shadow buffer") since it's really only useful for skinning purposes (though this means the VBO has to be readable for static geometry to work). --- components/nifogre/ogrenifloader.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f8eca821ff..6083238808 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -845,8 +845,13 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); std::vector srcVerts = data->vertices; std::vector srcNorms = data->normals; + Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; + bool vertShadowBuffer = false; if(skin != NULL) { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be // explicitly attached later. mesh->setSkeletonName(mName); @@ -948,8 +953,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcVerts.size()) { vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcVerts.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, - true); + srcVerts.size(), vertUsage, vertShadowBuffer); vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); @@ -960,8 +964,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcNorms.size()) { vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcNorms.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, - true); + srcNorms.size(), vertUsage, vertShadowBuffer); vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); @@ -980,8 +983,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader rs->convertColourValue(clr, &colorsRGB[i]); } vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, - true); + colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); bind->setBinding(nextBuf++, vbuf); @@ -993,7 +995,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size()*numUVs, - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); + Ogre::HardwareBuffer::HBU_STATIC); for(size_t i = 0;i < numUVs;i++) { const std::vector &uvlist = data->uvlist[i]; @@ -1009,7 +1011,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcIdx.size()) { ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); + Ogre::HardwareBuffer::HBU_STATIC); ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); sub->indexData->indexBuffer = ibuf; sub->indexData->indexCount = srcIdx.size(); From ee0a20f9ce30cd885a3110df97b6e911095d5d7f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 07:00:24 -0700 Subject: [PATCH 0912/1483] Read some missing particle data from NIFs --- components/nif/data.hpp | 13 +++++++++---- components/nif/nifstream.hpp | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 9bdba63961..68ffd19b8f 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -167,6 +167,10 @@ class NiAutoNormalParticlesData : public ShapeData public: int activeCount; + float activeRadius; + + std::vector sizes; + void read(NIFStream *nif) { ShapeData::read(nif); @@ -174,14 +178,13 @@ public: // Should always match the number of vertices activeCount = nif->getUShort(); - // Skip all the info, we don't support particles yet - nif->getFloat(); // Active radius ? + activeRadius = nif->getFloat(); nif->getUShort(); // Number of valid entries in the following arrays ? if(nif->getInt()) { // Particle sizes - nif->skip(activeCount * sizeof(float)); + nif->getFloats(sizes, activeCount); } } }; @@ -189,6 +192,8 @@ public: class NiRotatingParticlesData : public NiAutoNormalParticlesData { public: + std::vector rotations; + void read(NIFStream *nif) { NiAutoNormalParticlesData::read(nif); @@ -198,7 +203,7 @@ public: // Rotation quaternions. I THINK activeCount is correct here, // but verts (vertex number) might also be correct, if there is // any case where the two don't match. - nif->skip(activeCount * 4*sizeof(float)); + nif->getQuaternions(rotations, activeCount); } } }; diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 02b931b7ed..a2595d17b8 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -168,6 +168,12 @@ public: for(size_t i = 0;i < vec.size();i++) vec[i] = getVector4(); } + void getQuaternions(std::vector &quat, size_t size) + { + quat.resize(size); + for(size_t i = 0;i < quat.size();i++) + quat[i] = getQuaternion(); + } }; } From 2f6ae4a915e1a26f75afd6993dd0b06ab40a211b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 20:56:35 -0700 Subject: [PATCH 0913/1483] Read more particle information --- components/nif/controller.hpp | 79 ++++++++++++++++++++++++++++++++--- components/nif/data.hpp | 18 ++++---- components/nif/recordptr.hpp | 1 + 3 files changed, 82 insertions(+), 16 deletions(-) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 8331b93b7d..2ff25a274b 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -62,20 +62,87 @@ public: } }; -class NiBSPArrayController : public Controller +class NiParticleSystemController : public Controller { public: + float velocity; + float velocityRandom; + + float verticalDir; // 0=up, pi/2=horizontal, pi=down + float verticalAngle; + float horizontalDir; + float horizontalAngle; + + float size; + float startTime; + float stopTime; + + float emitRate; + float lifetime; + float lifetimeRandom; + + int emitFlags; // Bit 0: Emit Rate toggle bit (0 = auto adjust, 1 = use Emit Rate value) + Ogre::Vector3 offsetRandom; + + NodePtr emitter; + + int numParticles; + int activeCount; + //std::vector particles; /*numParticles*/ + + RecordPtr modifier; + void read(NIFStream *nif) { Controller::read(nif); - // At the moment, just skip it all - nif->skip(111); - int s = nif->getUShort(); - nif->skip(15 + s*40); + velocity = nif->getFloat(); + velocityRandom = nif->getFloat(); + verticalDir = nif->getFloat(); + verticalAngle = nif->getFloat(); + horizontalDir = nif->getFloat(); + horizontalAngle = nif->getFloat(); + /*normal?*/ nif->getVector3(); + /*color?*/ nif->getVector4(); + size = nif->getFloat(); + startTime = nif->getFloat(); + stopTime = nif->getFloat(); + nif->getChar(); + emitRate = nif->getFloat(); + lifetime = nif->getFloat(); + lifetimeRandom = nif->getFloat(); + + emitFlags = nif->getUShort(); + offsetRandom = nif->getVector3(); + + emitter.read(nif); + + /* Unknown Short, 0? + * Unknown Float, 1.0? + * Unknown Int, 1? + * Unknown Int, 0? + * Unknown Short, 0? + */ + nif->skip(16); + + numParticles = nif->getUShort(); + activeCount = nif->getUShort(); + nif->skip(numParticles*40); + + nif->getUInt(); /* -1? */ + modifier.read(nif); + nif->getUInt(); /* -1? */ + nif->getChar(); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + emitter.post(nif); + modifier.post(nif); } }; -typedef NiBSPArrayController NiParticleSystemController; +typedef NiParticleSystemController NiBSPArrayController; class NiMaterialColorController : public Controller { diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 68ffd19b8f..a2c9bb56db 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -165,9 +165,9 @@ public: class NiAutoNormalParticlesData : public ShapeData { public: - int activeCount; + float particleSize; - float activeRadius; + int activeCount; std::vector sizes; @@ -176,15 +176,15 @@ public: ShapeData::read(nif); // Should always match the number of vertices - activeCount = nif->getUShort(); + nif->getUShort(); - activeRadius = nif->getFloat(); - nif->getUShort(); // Number of valid entries in the following arrays ? + particleSize = nif->getFloat(); + activeCount = nif->getUShort(); if(nif->getInt()) { // Particle sizes - nif->getFloats(sizes, activeCount); + nif->getFloats(sizes, vertices.size()); } } }; @@ -200,10 +200,8 @@ public: if(nif->getInt()) { - // Rotation quaternions. I THINK activeCount is correct here, - // but verts (vertex number) might also be correct, if there is - // any case where the two don't match. - nif->getQuaternions(rotations, activeCount); + // Rotation quaternions. + nif->getQuaternions(rotations, vertices.size()); } } }; diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index c5bafea124..b7cd122bcb 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -142,6 +142,7 @@ class NiSourceTexture; class NiRotatingParticlesData; class NiAutoNormalParticlesData; +typedef RecordPtrT RecordPtr; typedef RecordPtrT NodePtr; typedef RecordPtrT ExtraPtr; typedef RecordPtrT NiUVDataPtr; From ac10c5f05cd94034d3ee6b4a0ed97dc9518a8fc9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 01:26:57 -0700 Subject: [PATCH 0914/1483] Even more particle information --- components/nif/controlled.hpp | 8 +++++--- components/nif/controller.hpp | 29 ++++++++++++++++++++++++----- components/nif/recordptr.hpp | 1 - 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 36c9a82ace..08c47defee 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -66,12 +66,14 @@ typedef Named NiSequenceStreamHelper; class NiParticleGrowFade : public Controlled { public: + float growTime; + float fadeTime; + void read(NIFStream *nif) { Controlled::read(nif); - - // Two floats. - nif->skip(8); + growTime = nif->getFloat(); + fadeTime = nif->getFloat(); } }; diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 2ff25a274b..aa6a9ef4ff 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -65,6 +65,14 @@ public: class NiParticleSystemController : public Controller { public: + struct Particle { + Ogre::Vector3 velocity; + float lifetime; + float lifespan; + float timestamp; + int vertex; + }; + float velocity; float velocityRandom; @@ -88,9 +96,9 @@ public: int numParticles; int activeCount; - //std::vector particles; /*numParticles*/ + std::vector particles; - RecordPtr modifier; + ExtraPtr extra; void read(NIFStream *nif) { @@ -127,10 +135,21 @@ public: numParticles = nif->getUShort(); activeCount = nif->getUShort(); - nif->skip(numParticles*40); + + particles.resize(numParticles); + for(size_t i = 0;i < particles.size();i++) + { + particles[i].velocity = nif->getVector3(); + nif->getVector3(); /* unknown */ + particles[i].lifetime = nif->getFloat(); + particles[i].lifespan = nif->getFloat(); + particles[i].timestamp = nif->getFloat(); + nif->getUShort(); /* unknown */ + particles[i].vertex = nif->getUShort(); + } nif->getUInt(); /* -1? */ - modifier.read(nif); + extra.read(nif); nif->getUInt(); /* -1? */ nif->getChar(); } @@ -139,7 +158,7 @@ public: { Controller::post(nif); emitter.post(nif); - modifier.post(nif); + extra.post(nif); } }; typedef NiParticleSystemController NiBSPArrayController; diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index b7cd122bcb..c5bafea124 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -142,7 +142,6 @@ class NiSourceTexture; class NiRotatingParticlesData; class NiAutoNormalParticlesData; -typedef RecordPtrT RecordPtr; typedef RecordPtrT NodePtr; typedef RecordPtrT ExtraPtr; typedef RecordPtrT NiUVDataPtr; From 77ba0fbe730ff6d9e7a20126df177054d183eed2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 01:31:05 -0700 Subject: [PATCH 0915/1483] Prepare for creating particles This adds a vector of ParticleSystems to the EntityList, and modifies corresponding code to handle it. It also loads the ParticleFX plugin so particles can be created (although they aren't yet). --- apps/openmw/mwrender/animation.cpp | 3 +++ apps/openmw/mwrender/npcanimation.cpp | 6 +++--- apps/openmw/mwrender/objects.cpp | 13 ++++++++++++- components/nifogre/ogrenifloader.hpp | 4 +++- libs/openengine/ogre/renderer.cpp | 1 + 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cc926e685d..fd575f9183 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -40,9 +40,12 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < mEntityList.mParticles.size();i++) + sceneMgr->destroyParticleSystem(mEntityList.mParticles[i]); for(size_t i = 0;i < mEntityList.mEntities.size();i++) sceneMgr->destroyEntity(mEntityList.mEntities[i]); } + mEntityList.mParticles.clear(); mEntityList.mEntities.clear(); mEntityList.mSkelBase = NULL; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b76a38c469..f1af6a7d3c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -363,11 +363,11 @@ void NpcAnimation::removeEntities(NifOgre::EntityList &entities) assert(&entities != &mEntityList); Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < entities.mParticles.size();i++) + sceneMgr->destroyParticleSystem(entities.mParticles[i]); for(size_t i = 0;i < entities.mEntities.size();i++) - { - entities.mEntities[i]->detachFromParent(); sceneMgr->destroyEntity(entities.mEntities[i]); - } + entities.mParticles.clear(); entities.mEntities.clear(); entities.mSkelBase = NULL; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 50c0210649..8c5d4cad3a 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -156,7 +158,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool } } - if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || anyTransparency) + if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || + anyTransparency || entities.mParticles.size() > 0) { for(size_t i = 0;i < entities.mEntities.size();i++) { @@ -169,6 +172,14 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } + for(size_t i = 0;i < entities.mParticles.size();i++) + { + Ogre::ParticleSystem *part = entities.mParticles[i]; + // TODO: Check the particle system's material for actual transparency + part->setRenderQueueGroup(RQG_Alpha); + part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); + part->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); + } } else { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 92b153468a..e6672541bd 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -40,8 +40,10 @@ namespace NifOgre typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { - std::vector mEntities; Ogre::Entity *mSkelBase; + std::vector mEntities; + + std::vector mParticles; EntityList() : mSkelBase(0) { } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 309ba8a060..05760ffa98 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -195,6 +195,7 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); + Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) From b5719e0ec7051d139de32023577c630124842c9f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 05:08:12 -0700 Subject: [PATCH 0916/1483] Create particle systems for NiAutoNormalParticles and NiRotatingParticles nodes Very incomplete, but it's something to work with. --- components/nifogre/ogrenifloader.cpp | 171 +++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6083238808..6d08d4ffcc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -317,7 +319,9 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ - node->recType == Nif::RC_NiTriShape /* Handled in the mesh loader */ + node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); @@ -326,7 +330,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); - else + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController + )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } @@ -588,7 +593,8 @@ static std::string findTextureName(const std::string &filename) } public: -static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, +static Ogre::String getMaterial(const Nif::ShapeData *shapedata, + const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, @@ -617,7 +623,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int specFlags = 0; Ogre::String texName[7]; - bool vertexColour = (shape->data->colors.size() != 0); + bool vertexColour = (shapedata->colors.size() != 0); // Texture if(texprop) @@ -819,12 +825,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mGroup; size_t mShapeIndex; - void warn(const std::string &msg) + static void warn(const std::string &msg) { std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; } - void fail(const std::string &msg) + static void fail(const std::string &msg) { std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; abort(); @@ -1039,9 +1045,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } bool needTangents=false; - std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup, + std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, - vertprop, zprop, specprop, needTangents); + vertprop, zprop, specprop, + needTangents); if(matname.length() > 0) sub->setMaterialName(matname); @@ -1114,6 +1121,146 @@ class NIFMeshLoader : Ogre::ManualResourceLoader static LoaderMap sLoaders; + static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) + { + Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); + emitter->setDirection(Ogre::Vector3::UNIT_Z); + emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, + partctrl->velocity+partctrl->velocityRandom); + emitter->setEmissionRate(partctrl->emitRate); + emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, + partctrl->lifetime+partctrl->lifetimeRandom); + + Nif::ExtraPtr e = partctrl->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiParticleGrowFade) + { + // TODO: Implement + } + else if(e->recType == Nif::RC_NiParticleColorModifier) + { + // TODO: Implement (Ogre::ColourInterpolatorAffector?) + } + else if(e->recType == Nif::RC_NiGravity) + { + // TODO: Implement (Ogre::LinearForceAffector?) + } + else + warn("Unhandled particle modifier "+e->recName); + e = e->extra; + } + } + + Ogre::ParticleSystem *createParticleSystem(Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, + const Nif::Node *partnode) + { + const Nif::NiAutoNormalParticlesData *particledata = NULL; + if(partnode->recType == Nif::RC_NiAutoNormalParticles) + particledata = static_cast(partnode)->data.getPtr(); + else if(partnode->recType == Nif::RC_NiRotatingParticles) + particledata = static_cast(partnode)->data.getPtr(); + + Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); + try { + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + if(partnode->parent) + { + // FIXME: We should probably search down the whole tree instead of just the parent + const Nif::PropertyList &proplist = partnode->parent->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + } + const Nif::PropertyList &proplist = partnode->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + + std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + + bool needTangents; + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + needTangents)); + + partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); + partsys->setCullIndividually(false); + partsys->setParticleQuota(particledata->activeCount); + + Nif::ControllerPtr ctrl = partnode->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiParticleSystemController) + { + const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); + + createParticleEmitterAffectors(partsys, partctrl); + if(!partctrl->emitter.empty() && !partsys->isAttached()) + entitybase->attachObjectToBone(partctrl->emitter->name, partsys); + } + ctrl = ctrl->next; + } + + if(!partsys->isAttached()) + entitybase->attachObjectToBone(partnode->name, partsys); + } + catch(std::exception &e) { + std::cerr<< "Particles exception: "<destroyParticleSystem(partsys); + partsys = NULL; + }; + return partsys; + } + + NIFMeshLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1199,6 +1346,14 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } + if((node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x01)) + { + Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); + if(partsys != NULL) + entities.mParticles.push_back(partsys); + } + const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { From 73da794d77c8d2552bf478478f43b54e4c45d028 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 14:34:39 +0200 Subject: [PATCH 0917/1483] added basic race table --- apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadrace.cpp | 21 +++++++++++++++++++++ components/esm/loadrace.hpp | 3 +++ 9 files changed, 64 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d62fd7267b..c596bb162d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -66,11 +66,17 @@ CSMWorld::Data::Data() for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); + mRaces.addColumn (new StringIdColumn); + mRaces.addColumn (new RecordStateColumn); + mRaces.addColumn (new NameColumn); + mRaces.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); + addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); } CSMWorld::Data::~Data() @@ -129,6 +135,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getFactions() return mFactions; } +const CSMWorld::IdCollection& CSMWorld::Data::getRaces() const +{ + return mRaces; +} + +CSMWorld::IdCollection& CSMWorld::Data::getRaces() +{ + return mRaces; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -168,6 +184,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SKIL: mSkills.load (reader, base); break; case ESM::REC_CLAS: mClasses.load (reader, base); break; case ESM::REC_FACT: mFactions.load (reader, base); break; + case ESM::REC_RACE: mRaces.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 16a9685a53..6b729728f5 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -26,6 +27,7 @@ namespace CSMWorld IdCollection mSkills; IdCollection mClasses; IdCollection mFactions; + IdCollection mRaces; std::vector mModels; std::map mModelIndex; @@ -62,6 +64,10 @@ namespace CSMWorld IdCollection& getFactions(); + const IdCollection& getRaces() const; + + IdCollection& getRaces(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 985cab0d4c..2e5e6a0a0a 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -22,6 +22,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -33,6 +34,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 0190467c4b..2213e15f31 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -43,7 +43,9 @@ namespace CSMWorld Type_Classes, Type_Class, Type_Factions, - Type_Faction + Type_Faction, + Type_Races, + Type_Race }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 83b333c04e..e12929cf2e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -101,6 +101,10 @@ void CSVDoc::View::setupWorldMenu() QAction *factions = new QAction (tr ("Factions"), this); connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); world->addAction (factions); + + QAction *races = new QAction (tr ("Races"), this); + connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView())); + world->addAction (races); } void CSVDoc::View::setupUi() @@ -271,6 +275,11 @@ void CSVDoc::View::addFactionsSubView() addSubView (CSMWorld::UniversalId::Type_Factions); } +void CSVDoc::View::addRacesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Races); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 03905430a8..4132d73b20 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -121,6 +121,8 @@ namespace CSVDoc void addClassesSubView(); void addFactionsSubView(); + + void addRacesSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index de36594a58..d5ba273776 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -19,6 +19,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Globals, CSMWorld::UniversalId::Type_Classes, CSMWorld::UniversalId::Type_Factions, + CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 94aa792bc6..955424e2b9 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -30,4 +30,25 @@ void Race::save(ESMWriter &esm) esm.writeHNOString("DESC", mDescription); } + void Race::blank() + { + mName.clear(); + mDescription.clear(); + + mPowers.mList.clear(); + + for (int i=0; i<7; ++i) + { + mData.mBonus[i].mSkill = -1; + mData.mBonus[i].mBonus = 0; + } + + for (int i=0; i<8; ++i) + mData.mAttributeValues[i].mMale = mData.mAttributeValues[i].mFemale = 1; + + mData.mHeight.mMale = mData.mHeight.mFemale = 1; + mData.mWeight.mMale = mData.mWeight.mFemale = 1; + + mData.mFlags = 0; + } } diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 845956686c..6ecec8ebb9 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -66,6 +66,9 @@ struct Race void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } From 48a88f1917d00eccb9c2e490f13f3dc335c240be Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Apr 2013 15:10:27 +0200 Subject: [PATCH 0918/1483] Fix startRandomTitle --- apps/openmw/mwsound/soundmanagerimp.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1b07dfe627..69e3016767 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -208,14 +208,21 @@ namespace MWSound void SoundManager::startRandomTitle() { - Ogre::StringVectorPtr filelist; - filelist = mResourceMgr.findResourceNames(Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "Music/"+mCurrentPlaylist+"/*"); - if(!filelist->size()) + Ogre::StringVector filelist; + + Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); + for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + { + Ogre::StringVectorPtr resourcesInThisGroup = mResourceMgr.findResourceNames(*it, + "Music/"+mCurrentPlaylist+"/*"); + filelist.insert(filelist.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); + } + + if(!filelist.size()) return; - int i = rand()%filelist->size(); - streamMusicFull((*filelist)[i]); + int i = rand()%filelist.size(); + streamMusicFull(filelist[i]); } bool SoundManager::isMusicPlaying() From 2e7d5377f40b257186f21e939e370e298c5b51f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Apr 2013 16:51:22 +0200 Subject: [PATCH 0919/1483] Fix crash when moving npcs to an inactive cell --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- .../mwscript/transformationextensions.cpp | 4 ++-- apps/openmw/mwworld/scene.cpp | 14 +++++------ apps/openmw/mwworld/worldimp.cpp | 24 ++++++++++++++----- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2f49a40316..cd5ab19b9d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -235,7 +235,7 @@ void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) mObjects.buildStaticGeometry (*store); mDebugging->cellAdded(store); if (store->mCell->isExterior()) - mTerrainManager->cellAdded(store); + mTerrainManager->cellAdded(store); waterAdded(store); } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 000cc545db..97dc6d7188 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -304,7 +304,7 @@ namespace MWScript } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); - MWBase::Environment::get().getWorld()->adjustPosition(ptr); + MWWorld::Class::get(ptr).adjustPosition(ptr); } else { @@ -343,7 +343,7 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); - MWBase::Environment::get().getWorld()->adjustPosition(ptr); + MWWorld::Class::get(ptr).adjustPosition(ptr); } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c8853f4842..2244a4fc64 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -115,11 +115,6 @@ namespace MWWorld if(result.second) { - /// \todo rescale depending on the state of a new GMST - insertCell (*cell, true); - - mRendering.cellAdded (cell); - float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; @@ -142,6 +137,11 @@ namespace MWWorld } } + /// \todo rescale depending on the state of a new GMST + insertCell (*cell, true); + + mRendering.cellAdded (cell); + mRendering.configureAmbient(*cell); mRendering.requestMap(cell); mRendering.configureAmbient(*cell); @@ -166,7 +166,7 @@ namespace MWWorld float z = Ogre::Radian(pos.rot[2]).valueDegrees(); world->rotateObject(player, x, y, z); - world->adjustPosition(player); + MWWorld::Class::get(player).adjustPosition(player); } MWBase::MechanicsManager *mechMgr = @@ -358,7 +358,7 @@ namespace MWWorld float z = Ogre::Radian(position.rot[2]).valueDegrees(); world->rotateObject(world->getPlayer().getPlayer(), x, y, z); - world->adjustPosition(world->getPlayer().getPlayer()); + MWWorld::Class::get(world->getPlayer().getPlayer()).adjustPosition(world->getPlayer().getPlayer()); return; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2ce753b816..ae9b7a06b7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -706,6 +706,7 @@ namespace MWWorld void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { ESM::Position &pos = ptr.getRefData().getPosition(); + pos.pos[0] = x; pos.pos[1] = y; pos.pos[2] = z; @@ -718,7 +719,7 @@ namespace MWWorld if (*currCell != newCell) { - removeContainerScripts(ptr); + removeContainerScripts(ptr); if (isPlayer) { @@ -750,7 +751,7 @@ namespace MWWorld else { MWWorld::Ptr copy = - MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + MWWorld::Class::get(ptr).copyToCell(ptr, newCell, pos); mRendering->updateObjectCell(ptr, copy); @@ -780,12 +781,14 @@ namespace MWWorld bool World::moveObjectImp(const Ptr& ptr, float x, float y, float z) { CellStore *cell = ptr.getCell(); + if (cell->isExterior()) { int cellX, cellY; positionToIndex(x, y, cellX, cellY); cell = getExterior(cellX, cellY); } + moveObject(ptr, *cell, x, y, z); return cell != ptr.getCell(); @@ -827,6 +830,19 @@ namespace MWWorld { Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); + if(!ptr.getRefData().getBaseNode()) + { + // will be adjusted when Ptr's cell becomes active + return; + } + + float terrainHeight = mRendering->getTerrainHeightAt(pos); + + if (pos.z < terrainHeight) + pos.z = terrainHeight+400; // place slightly above. will snap down to ground with code below + + ptr.getRefData().getPosition().pos[2] = pos.z; + if (!isFlying(ptr)) { Ogre::Vector3 traced = mPhysics->traceDown(ptr); @@ -834,10 +850,6 @@ namespace MWWorld pos.z = traced.z; } - float terrainHeight = mRendering->getTerrainHeightAt(pos); - if (pos.z < terrainHeight) - pos.z = terrainHeight; - moveObject(ptr, pos.x, pos.y, pos.z); } From 076831c9cc5dc0bf9b9bc864eff82a4715856b7b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 5 Apr 2013 12:48:05 +0200 Subject: [PATCH 0920/1483] added flag columns to race table --- apps/opencs/model/world/columns.hpp | 34 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 2 ++ 2 files changed, 36 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index dfabaaf2cf..ad6916ae2b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -434,6 +434,40 @@ namespace CSMWorld return true; } }; + + template + struct FlagColumn : public Column + { + int mMask; + + FlagColumn (const std::string& name, int mask) + : Column (name, ColumnBase::Display_Boolean), mMask (mask) + {} + + virtual QVariant get (const Record& record) const + { + return (record.get().mData.mFlags & mMask)!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + int flags = record.get().mData.mFlags & ~mMask; + + if (data.toInt()) + flags |= mMask; + + record2.mData.mFlags = flags; + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c596bb162d..18ff5aac1a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -70,6 +70,8 @@ CSMWorld::Data::Data() mRaces.addColumn (new RecordStateColumn); mRaces.addColumn (new NameColumn); mRaces.addColumn (new DescriptionColumn); + mRaces.addColumn (new FlagColumn ("Playable", 0x1)); + mRaces.addColumn (new FlagColumn ("Beast Race", 0x2)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 35fe828108a2ab9b8f71071e3a9e1ec693e39d78 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 5 Apr 2013 13:46:48 +0200 Subject: [PATCH 0921/1483] added race table weight/height columns --- apps/opencs/model/world/columns.hpp | 40 ++++++++++++++++++++++++++++- apps/opencs/model/world/data.cpp | 4 +++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index ad6916ae2b..f65f212da1 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -453,7 +453,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - int flags = record.get().mData.mFlags & ~mMask; + int flags = record2.mData.mFlags & ~mMask; if (data.toInt()) flags |= mMask; @@ -468,6 +468,44 @@ namespace CSMWorld return true; } }; + + template + struct WeightHeightColumn : public Column + { + bool mMale; + bool mWeight; + + WeightHeightColumn (bool male, bool weight) + : Column (male ? (weight ? "Male Weight" : "Male Height") : + (weight ? "Female Weight" : "Female Height"), ColumnBase::Display_Float), + mMale (male), mWeight (weight) + {} + + virtual QVariant get (const Record& record) const + { + const ESM::Race::MaleFemaleF& value = + mWeight ? record.get().mData.mWeight : record.get().mData.mHeight; + + return mMale ? value.mMale : value.mFemale; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + ESM::Race::MaleFemaleF& value = + mWeight ? record2.mData.mWeight : record2.mData.mHeight; + + (mMale ? value.mMale : value.mFemale) = data.toFloat(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 18ff5aac1a..fb835b986a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -72,6 +72,10 @@ CSMWorld::Data::Data() mRaces.addColumn (new DescriptionColumn); mRaces.addColumn (new FlagColumn ("Playable", 0x1)); mRaces.addColumn (new FlagColumn ("Beast Race", 0x2)); + mRaces.addColumn (new WeightHeightColumn (true, true)); + mRaces.addColumn (new WeightHeightColumn (true, false)); + mRaces.addColumn (new WeightHeightColumn (false, true)); + mRaces.addColumn (new WeightHeightColumn (false, false)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From dc9f5f93e74567acf0b3975e7328ba702bbd4003 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 05:14:24 -0700 Subject: [PATCH 0922/1483] Use a helper function to get node properties --- components/nifogre/ogrenifloader.cpp | 155 ++++++++++----------------- 1 file changed, 56 insertions(+), 99 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6d08d4ffcc..4b0f9ce3dc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -836,15 +836,44 @@ class NIFMeshLoader : Ogre::ManualResourceLoader abort(); } + static void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop) + { + if(node->parent) + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop); + + const Nif::PropertyList &proplist = node->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + } // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -1044,7 +1073,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool needTangents=false; + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + bool needTangents = false; + + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, @@ -1061,42 +1098,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node) { - // Scan the property list for material information - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop, specprop); + handleNiTriShape(mesh, dynamic_cast(node)); return true; } @@ -1108,7 +1114,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop, specprop)) + if(findTriShape(mesh, children[i].getPtr())) return true; } } @@ -1163,69 +1169,20 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); try { + std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + const Nif::NiTexturingProperty *texprop = NULL; const Nif::NiMaterialProperty *matprop = NULL; const Nif::NiAlphaProperty *alphaprop = NULL; const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; - if(partnode->parent) - { - // FIXME: We should probably search down the whole tree instead of just the parent - const Nif::PropertyList &proplist = partnode->parent->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; + bool needTangents = false; - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - } - const Nif::PropertyList &proplist = partnode->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - - bool needTangents; + getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, @@ -1280,7 +1237,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } const Nif::Node *node = dynamic_cast(nif->getRecord(0)); - findTriShape(mesh, node, NULL, NULL, NULL, NULL, NULL, NULL); + findTriShape(mesh, node); } void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) From 12fada28622c329b1119b6e5b6d0fae10e207eb7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 05:34:59 -0700 Subject: [PATCH 0923/1483] Don't offset the animation time to 0 --- components/nifogre/ogrenifloader.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 4b0f9ce3dc..f663cdf145 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -167,7 +167,7 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { - Ogre::Animation *anim = skel->createAnimation(name, stopTime-startTime); + Ogre::Animation *anim = skel->createAnimation(name, stopTime); for(size_t i = 0;i < ctrls.size();i++) { @@ -246,7 +246,7 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const } Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime-startTime); + kframe = nodetrack->createNodeKeyFrame(curtime); if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) kframe->setRotation(curquat); else @@ -441,16 +441,15 @@ void loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - TextKeyMap::const_iterator insiter = keyiter; + TextKeyMap::const_iterator insiter(keyiter); TextKeyMap groupkeys; do { sep = insiter->second.find(':'); if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first - keyiter->first, - insiter->second.substr(sep+2))); + groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); + groupkeys.insert(std::make_pair(insiter->first, insiter->second)); } while(insiter++ != lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); From bf0ae3ae72bb5f0d291d037b41f326707f65b21c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 06:29:14 -0700 Subject: [PATCH 0924/1483] Read NiVisData info --- components/nif/data.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index a2c9bb56db..c13495ff8b 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -297,13 +297,17 @@ public: float time; char isSet; }; + std::vector mVis; void read(NIFStream *nif) { int count = nif->getInt(); - - /* Skip VisData */ - nif->skip(count*5); + mVis.resize(count); + for(size_t i = 0;i < mVis.size();i++) + { + mVis[i].time = nif->getFloat(); + mVis[i].isSet = nif->getChar(); + } } }; From 48d9885554cdddb7c813035f9d226228f91ac310 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 5 Apr 2013 15:42:05 +0200 Subject: [PATCH 0925/1483] Started bugfix #691 --- apps/openmw/mwclass/armor.cpp | 87 +++++++++++++++++++++ apps/openmw/mwclass/armor.hpp | 2 + apps/openmw/mwclass/clothing.cpp | 61 +++++++++++++++ apps/openmw/mwclass/clothing.hpp | 2 + apps/openmw/mwclass/weapon.cpp | 66 ++++++++++++++++ apps/openmw/mwclass/weapon.hpp | 2 + apps/openmw/mwmechanics/actors.cpp | 3 +- apps/openmw/mwworld/actionequip.cpp | 104 +------------------------ apps/openmw/mwworld/class.cpp | 5 ++ apps/openmw/mwworld/class.hpp | 3 + apps/openmw/mwworld/inventorystore.cpp | 6 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- 12 files changed, 237 insertions(+), 106 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 320944d3ce..496e695450 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,6 +16,8 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/player.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -290,6 +292,91 @@ namespace MWClass ref->mBase = record; } + bool Armor::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) + { + if(*slot == MWWorld::InventoryStore::Slot_Helmet) + { + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + + bool allow = true; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_Head) + { + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); + + allow = false; + break; + } + } + + if(!allow) + break; + } + + if (*slot == MWWorld::InventoryStore::Slot_Boots) + { + bool allow = true; + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) + { + allow = false; + // Only notify the player, not npcs + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); + } + break; + } + } + + if(!allow) + return false; + } + + } + } + return true; + } + boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 65f49abb7d..bb07e42b03 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,6 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index abad267675..77a7557bf6 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/player.hpp" #include "../mwgui/tooltips.hpp" @@ -237,6 +238,66 @@ namespace MWClass ref->mBase = record; } + bool Clothing::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) + { + if (*slot == MWWorld::InventoryStore::Slot_Boots) + { + bool allow = true; + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) + { + allow = false; + // Only notify the player, not npcs + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); + } + break; + } + } + + if(!allow) + return false; + } + + } + } + return true; + } + boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index c3ef22f113..4978fa2288 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,6 +61,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0a527262f8..51e8130039 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,6 +384,72 @@ namespace MWClass ref->mBase = record; } + bool Weapon::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + // equip the item in the first free slot + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) + { + if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + } + } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + } + } + return true; + } + return false; + } + boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 4774bb50be..922cd165f2 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,6 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f60567c6c4..89671ee086 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -36,8 +36,7 @@ namespace MWMechanics void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) { if (!paused && ptr.getRefData().getHandle()!="player") - MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip ( - MWWorld::Class::get (ptr).getNpcStats (ptr)); + MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip (ptr); } void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 9a44a99791..c147113fc6 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,108 +43,8 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - - // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); - if(race->mData.mFlags & ESM::Race::Beast) - { - if(*slot == MWWorld::InventoryStore::Slot_Helmet) - { - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - - bool allow = true; - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_Head) - { - if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - allow = false; - break; - } - } - - if(!allow) - break; - } - - if (*slot == MWWorld::InventoryStore::Slot_Boots) - { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) - { - allow = false; - // Only notify the player, not npcs - if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { - if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); - } - - else // It's boots - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - } - } - break; - } - } - - if(!allow) - break; - } - - } - - //Disable twohanded when shield equipped, shield when twohanded equipped - if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) - { - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - } - } - } - if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) - { - ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } - } - } + if(!MWWorld::Class::get(getTarget()).canEquip(actor,getTarget())) + break; // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2dfa241b3b..ee2072cf09 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,6 +259,11 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } + bool Class::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + return true; + } + void Class::adjustPosition(const MWWorld::Ptr& ptr) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index de4741e38b..4931da7a86 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,6 +242,9 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. Unequip twohanded item if neccesary + virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index dd518ff6a4..7a5ae38d0e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -128,8 +128,9 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return mSlots[slot]; } -void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) +void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) { + const MWMechanics::NpcStats& stats = MWWorld::Class::get(npc).getNpcStats(npc); TSlots slots; initSlots (slots); @@ -183,6 +184,9 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) } } + if(!MWWorld::Class::get (test).canEquip (npc, test)) + continue; + if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { // unstack item pointed to by iterator if required diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index e55eca0ae7..cc28a0a0c0 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -78,7 +78,7 @@ namespace MWWorld ContainerStoreIterator getSlot (int slot); - void autoEquip (const MWMechanics::NpcStats& stats); + void autoEquip (const MWWorld::Ptr& npc); ///< Auto equip items according to stats and item value. const MWMechanics::MagicEffects& getMagicEffects(); From af2a38db3854ecae1c6cdf056ed80b93146fe036 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 08:27:26 -0700 Subject: [PATCH 0926/1483] Fix looping anims that dont have "loop start" --- apps/openmw/mwrender/animation.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fd575f9183..8dbd8d8073 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -307,7 +307,15 @@ void Animation::reset(const std::string &start, const std::string &stop) else { mNextKey = mCurrentKeys->begin(); - mCurrentTime = 0.0f; + while(mNextKey != mCurrentKeys->end() && mNextKey->second != "start") + mNextKey++; + if(mNextKey != mCurrentKeys->end()) + mCurrentTime = mNextKey->first; + else + { + mNextKey = mCurrentKeys->begin(); + mCurrentTime = 0.0f; + } } if(stop.length() > 0) From 75b462b9744f1660af0374bc43c984e796008c24 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Apr 2013 18:23:22 +0200 Subject: [PATCH 0927/1483] If alpha rejection was forced, we also need to force depth_write and depth_check --- components/nifogre/ogrenifloader.cpp | 1 + files/materials/objects.mat | 2 ++ 2 files changed, 3 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f8eca821ff..8f9d69f6e2 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -771,6 +771,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String { alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ alphaTest = result.second; + depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on } if((alphaFlags&1)) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 8740c82c34..49df4e3949 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -14,6 +14,7 @@ material openmw_objects_base is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default depth_write default + depth_check default alpha_rejection default transparent_sorting default @@ -38,6 +39,7 @@ material openmw_objects_base scene_blend $scene_blend alpha_rejection $alpha_rejection depth_write $depth_write + depth_check $depth_check transparent_sorting $transparent_sorting texture_unit diffuseMap From 0631b28646c5cfe12360be1356980db93e3ff050 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 10:13:54 -0700 Subject: [PATCH 0928/1483] Prepare for supporting controller objects --- apps/openmw/mwrender/animation.cpp | 7 +++++++ apps/openmw/mwrender/animation.hpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/npcanimation.cpp | 1 + components/nifogre/ogrenifloader.hpp | 2 ++ 4 files changed, 30 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8dbd8d8073..00196c9d47 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -45,6 +45,7 @@ Animation::~Animation() for(size_t i = 0;i < mEntityList.mEntities.size();i++) sceneMgr->destroyEntity(mEntityList.mEntities[i]); } + mEntityList.mControllers.clear(); mEntityList.mParticles.clear(); mEntityList.mEntities.clear(); mEntityList.mSkelBase = NULL; @@ -129,6 +130,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } + + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); + for(size_t i = 0;i < mEntityList.mControllers.size();i++) + mEntityList.mControllers[i].setSource(ctrlval); } @@ -457,6 +462,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } + for(size_t i = 0;i < mEntityList.mControllers.size();i++) + mEntityList.mControllers[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 7caf351694..3e7dee6db2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,6 +16,26 @@ namespace MWRender class Animation { protected: + class AnimationValue : public Ogre::ControllerValue + { + private: + Animation *mAnimation; + + public: + AnimationValue(Animation *anim) : mAnimation(anim) + { } + + virtual Ogre::Real getValue() const + { + return mAnimation->mCurrentTime; + } + + virtual void setValue(Ogre::Real value) + { + mAnimation->mCurrentTime = value; + } + }; + MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f1af6a7d3c..b7bcad5995 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -367,6 +367,7 @@ void NpcAnimation::removeEntities(NifOgre::EntityList &entities) sceneMgr->destroyParticleSystem(entities.mParticles[i]); for(size_t i = 0;i < entities.mEntities.size();i++) sceneMgr->destroyEntity(entities.mEntities[i]); + entities.mControllers.clear(); entities.mParticles.clear(); entities.mEntities.clear(); entities.mSkelBase = NULL; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index e6672541bd..819b4d8806 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -45,6 +45,8 @@ struct EntityList { std::vector mParticles; + std::vector > mControllers; + EntityList() : mSkelBase(0) { } }; From aa9df818a52574984406733edb7c916c7183b1c6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 10:38:27 -0700 Subject: [PATCH 0929/1483] Add support for NiVisController --- components/nifogre/ogrenifloader.cpp | 103 ++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f663cdf145..443b207103 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -62,6 +62,83 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { + +// FIXME: Should not be here. +class VisController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::Bone *mTarget; + + // FIXME: We are not getting all objects here. Skinned meshes get + // attached to the object's root node, and won't be connected via a + // TagPoint. + static void setVisible(Ogre::Node *node, int vis) + { + Ogre::Node::ChildNodeIterator iter = node->getChildIterator(); + while(iter.hasMoreElements()) + { + node = iter.getNext(); + setVisible(node, vis); + + Ogre::TagPoint *tag = dynamic_cast(node); + if(tag != NULL) + { + Ogre::MovableObject *obj = tag->getChildObject(); + if(obj != NULL) + obj->setVisible(vis); + } + } + } + + public: + Value(Ogre::Bone *target) : mTarget(target) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 1.0f; + } + + virtual void setValue(Ogre::Real value) + { + int vis = static_cast(value); + setVisible(mTarget, vis); + } + }; + + class Function : public Ogre::ControllerFunction + { + private: + std::vector mData; + + public: + Function(const Nif::NiVisData *data) + : Ogre::ControllerFunction(false), + mData(data->mVis) + { } + + virtual Ogre::Real calculate(Ogre::Real value) + { + if(mData.size() == 0) + return 1.0f; + + if(mData[0].time >= value) + return mData[0].isSet; + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > value) + return mData[i-1].isSet; + } + return mData.back().isSet; + } + }; +}; + + // Helper class that computes the bounding box and of a mesh class BoundsFinder { @@ -330,7 +407,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; @@ -1129,7 +1207,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); - emitter->setDirection(Ogre::Vector3::UNIT_Z); + emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); + emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, partctrl->velocity+partctrl->velocityRandom); emitter->setEmissionRate(partctrl->emitRate); @@ -1270,6 +1349,26 @@ class NIFMeshLoader : Ogre::ManualResourceLoader e = e->extra; } + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); + + const Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); + if(!target) target = node; + + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(target->name); + Ogre::SharedPtr > srcval; /* Filled in later */ + Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); + Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); + + entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } + if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = static_cast(node); From b1257620d90904571a49fb75ac2a2080051311ff Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 22:58:21 +0200 Subject: [PATCH 0930/1483] Some cleanup in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index db0a47d844..35fb3a598b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,16 @@ before_script: - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 - - cat CMakeCache.txt before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev + - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrand-dev libfreeimage-dev libpng-dev + - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev + - sudo apt-get install -qq libcg nvidia-cg-dev + - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev + - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: From 07d5d26b4a2f724553feb8ecacc9fe58ed15d9d2 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:02:44 +0200 Subject: [PATCH 0931/1483] Corrected typo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 35fb3a598b..b8ebe6275c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev - - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrand-dev libfreeimage-dev libpng-dev + - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libcg nvidia-cg-dev - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev From d999c0a91c692289b4a3aba805c72ae41e4adf15 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:18:10 +0200 Subject: [PATCH 0932/1483] Enabled addtional Ubuntu repositories. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b8ebe6275c..f383d82721 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ before_script: - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive + - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse partner" - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev From fb4f50ce8f577081bfdc796c9f6cbc998debcec9 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:28:44 +0200 Subject: [PATCH 0933/1483] Removed 'partner' repository. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f383d82721..61d5fa551c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ before_script: - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse partner" + - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev From a48d60b5e34ed1d6dcfe6396392ec40120bf5412 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:34:23 +0200 Subject: [PATCH 0934/1483] Changed packet name from nvidia-cg-dev to nvidia-cg-toolkit. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 61d5fa551c..c574572490 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ before_install: - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - - sudo apt-get install -qq libcg nvidia-cg-dev + - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev script: "make -j`grep -c processor /proc/cpuinfo`" From 99ff89d668b8d51a3f6b46af35a94bc26ef1d256 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:41:15 +0200 Subject: [PATCH 0935/1483] Lowered number of used CPUs for compilation. Enabled building of unit tests. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c574572490..ee26fd5c1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" @@ -16,7 +16,7 @@ before_install: - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev -script: "make -j`grep -c processor /proc/cpuinfo`" +script: "make -j4" branches: only: - master From 6529919102bde1d126121a5669cbb802949162dc Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:01:44 +0200 Subject: [PATCH 0936/1483] Enabled building of Gtest libary. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index ee26fd5c1b..96ce6d7eb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,6 @@ language: cpp compiler: - - gcc -before_script: - - mkdir build - - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 + - gcc before_install: - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" @@ -15,7 +11,17 @@ before_install: - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev + - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev + - sudo mkdir /usr/src/gtest/build + - cd /usr/src/gtest/build + - sudo cmake .. -DBUILD_SHARED_LIBS=1 + - sudo make -j4 + - sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so + - sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so +before_script: + - mkdir build + - cd build + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 script: "make -j4" branches: only: From 977da3eeb80d09d3eccc0d0f7cd19308e2e71472 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:18:14 +0200 Subject: [PATCH 0937/1483] Change back directory to the one where OpenMW is downloaded. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 96ce6d7eb2..8df94ca488 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: cpp compiler: - gcc before_install: + - pwd - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo apt-add-repository ppa:openmw/deps @@ -19,6 +20,7 @@ before_install: - sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so - sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so before_script: + - cd - - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 From 86457ce488b233141091b04487d1ed5d89ac4338 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:45:04 +0200 Subject: [PATCH 0938/1483] Enabled running of openmw test suite. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8df94ca488..9ed8b7526c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ language: cpp compiler: - gcc +branches: + only: + - master + - travis_ci_test before_install: - pwd - git submodule update --init --recursive @@ -24,11 +28,10 @@ before_script: - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -script: "make -j4" -branches: - only: - - master - - travis_ci_test +script: + - make -j4 +after_script: + - openmw_test_suite notifications: recipients: - lgromanowski+travis.ci@gmail.com From 05e7cfeb70c80ebb3fcaa0d9f984366e65988a7f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 01:04:41 +0200 Subject: [PATCH 0939/1483] Corrected path to the openmw test suite. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9ed8b7526c..54fff44e2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ compiler: branches: only: - master + - next - travis_ci_test before_install: - pwd @@ -31,7 +32,7 @@ before_script: script: - make -j4 after_script: - - openmw_test_suite + - ./openmw_test_suite notifications: recipients: - lgromanowski+travis.ci@gmail.com From 9ac56ce60e2d03761be32a3e83e947cdfc9f1f4e Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 01:24:38 +0200 Subject: [PATCH 0940/1483] Removed travis_ci_test branch from checked branches list. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 54fff44e2e..374b38ce08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ branches: only: - master - next - - travis_ci_test before_install: - pwd - git submodule update --init --recursive From 81615c1ae5ac4055ffbe8c6239ebdf6b8b7fb029 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:18:36 -0700 Subject: [PATCH 0941/1483] Add a custom GrowFade particle affector --- CMakeLists.txt | 1 + libs/openengine/ogre/particles.cpp | 146 +++++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 17 ++++ libs/openengine/ogre/renderer.cpp | 15 +++ libs/openengine/ogre/renderer.hpp | 2 + 5 files changed, 181 insertions(+) create mode 100644 libs/openengine/ogre/particles.cpp create mode 100644 libs/openengine/ogre/particles.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e1b8e32e5e..b6a1017906 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/fader.cpp + ${LIBDIR}/openengine/ogre/particles.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp new file mode 100644 index 0000000000..3453b7f3d7 --- /dev/null +++ b/libs/openengine/ogre/particles.cpp @@ -0,0 +1,146 @@ +#include "particles.hpp" + +#include +#include +#include +#include + +class GrowFadeAffector : public Ogre::ParticleAffector +{ +public: + /** Command object for grow_time (see Ogre::ParamCommand).*/ + class CmdGrowTime : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GrowFadeAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getGrowTime()); + } + void doSet(void *target, const Ogre::String &val) + { + GrowFadeAffector *self = static_cast(target); + self->setGrowTime(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for fade_time (see Ogre::ParamCommand).*/ + class CmdFadeTime : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GrowFadeAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getFadeTime()); + } + void doSet(void *target, const Ogre::String &val) + { + GrowFadeAffector *self = static_cast(target); + self->setFadeTime(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Default constructor. */ + GrowFadeAffector(Ogre::ParticleSystem *psys) : ParticleAffector(psys) + { + mGrowTime = 0.0f; + mFadeTime = 0.0f; + + mType = "GrowFade"; + + // Init parameters + if(createParamDictionary("GrowFadeAffector")) + { + Ogre::ParamDictionary *dict = getParamDictionary(); + + Ogre::String grow_title("grow_time"); + Ogre::String fade_title("fade_time"); + Ogre::String grow_descr("Time from begin to reach full size."); + Ogre::String fade_descr("Time from end to shrink."); + + dict->addParameter(Ogre::ParameterDef(grow_title, grow_descr, Ogre::PT_REAL), &msGrowCmd); + dict->addParameter(Ogre::ParameterDef(fade_title, fade_descr, Ogre::PT_REAL), &msFadeCmd); + } + } + + /** See Ogre::ParticleAffector. */ + void _initParticle(Ogre::Particle *particle) + { + const Ogre::Real life_time = particle->totalTimeToLive; + Ogre::Real particle_time = particle->timeToLive; + + Ogre::Real width = mParent->getDefaultWidth(); + Ogre::Real height = mParent->getDefaultHeight(); + if(life_time-particle_time < mGrowTime) + { + Ogre::Real scale = (life_time-particle_time) / mGrowTime; + width *= scale; + height *= scale; + } + if(particle_time < mFadeTime) + { + Ogre::Real scale = particle_time / mFadeTime; + width *= scale; + height *= scale; + } + particle->setDimensions(width, height); + } + + /** See Ogre::ParticleAffector. */ + void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + const Ogre::Real life_time = p->totalTimeToLive; + Ogre::Real particle_time = p->timeToLive; + + Ogre::Real width = mParent->getDefaultWidth(); + Ogre::Real height = mParent->getDefaultHeight(); + if(life_time-particle_time < mGrowTime) + { + Ogre::Real scale = (life_time-particle_time) / mGrowTime; + width *= scale; + height *= scale; + } + if(particle_time < mFadeTime) + { + Ogre::Real scale = particle_time / mFadeTime; + width *= scale; + height *= scale; + } + p->setDimensions(width, height); + } + } + + void setGrowTime(Ogre::Real time) + { + mGrowTime = time; + } + Ogre::Real getGrowTime() const + { return mGrowTime; } + + void setFadeTime(Ogre::Real time) + { + mFadeTime = time; + } + Ogre::Real getFadeTime() const + { return mFadeTime; } + + static CmdGrowTime msGrowCmd; + static CmdFadeTime msFadeCmd; + +protected: + Ogre::Real mGrowTime; + Ogre::Real mFadeTime; +}; +GrowFadeAffector::CmdGrowTime GrowFadeAffector::msGrowCmd; +GrowFadeAffector::CmdFadeTime GrowFadeAffector::msFadeCmd; + +Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleAffector *p = new GrowFadeAffector(psys); + mAffectors.push_back(p); + return p; +} diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp new file mode 100644 index 0000000000..d466bb0308 --- /dev/null +++ b/libs/openengine/ogre/particles.hpp @@ -0,0 +1,17 @@ +#ifndef OENGINE_OGRE_PARTICLES_H +#define OENGINE_OGRE_PARTICLES_H + +#include + +/** Factory class for GrowFadeAffector. */ +class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory +{ + /** See Ogre::ParticleAffectorFactory */ + Ogre::String getName() const + { return "GrowFade"; } + + /** See Ogre::ParticleAffectorFactory */ + Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); +}; + +#endif /* OENGINE_OGRE_PARTICLES_H */ diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 05760ffa98..c9e91968f5 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -1,5 +1,6 @@ #include "renderer.hpp" #include "fader.hpp" +#include "particles.hpp" #include "OgreRoot.h" #include "OgreRenderWindow.h" @@ -8,6 +9,8 @@ #include "OgreTextureManager.h" #include "OgreTexture.h" #include "OgreHardwarePixelBuffer.h" +#include +#include "OgreParticleAffectorFactory.h" #include @@ -24,6 +27,7 @@ using namespace Ogre; using namespace OEngine::Render; + #if defined(__APPLE__) && !defined(__LP64__) CustomRoot::CustomRoot(const Ogre::String& pluginFileName, @@ -106,6 +110,11 @@ void OgreRenderer::loadPlugins() void OgreRenderer::unloadPlugins() { + std::vector::iterator ai; + for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();ai++) + OGRE_DELETE (*ai); + mAffectorFactories.clear(); + #ifdef ENABLE_PLUGIN_GL delete mGLPlugin; mGLPlugin = NULL; @@ -197,6 +206,12 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); + Ogre::ParticleAffectorFactory *affector; + affector = OGRE_NEW GrowFadeAffectorFactory(); + Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); + mAffectorFactories.push_back(affector); + + RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded"); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 251dc9c54d..ea46f5ae62 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -40,6 +40,7 @@ namespace Ogre class SceneManager; class Camera; class Viewport; + class ParticleAffectorFactory; } namespace OEngine @@ -94,6 +95,7 @@ namespace OEngine Ogre::D3D9Plugin* mD3D9Plugin; #endif Fader* mFader; + std::vector mAffectorFactories; bool logging; public: From b5017e054309cbd77517d6256fb6ca50b92bf9d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:19:05 -0700 Subject: [PATCH 0942/1483] Implement NiParticleGrowFade --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 443b207103..4a388bf553 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1220,7 +1221,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(e->recType == Nif::RC_NiParticleGrowFade) { - // TODO: Implement + const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade"); + affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); + affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } else if(e->recType == Nif::RC_NiParticleColorModifier) { From 99b915e652c27bfe1bc0e53e2d5cec9d12796e75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:54:53 -0700 Subject: [PATCH 0943/1483] Fix some material warnings --- components/nifogre/ogrenifloader.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 54d2c8cf16..215462bac5 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -712,7 +712,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, continue; if(texprop->textures[i].texture.empty()) { - warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name+"\n"); + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); continue; } @@ -840,10 +840,14 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); } - for(int i = 1;i < 7;i++) + for(int i = 0;i < 7;i++) { + if(i == Nif::NiTexturingProperty::BaseTexture || + i == Nif::NiTexturingProperty::BumpTexture || + i == Nif::NiTexturingProperty::GlowTexture) + continue; if(!texName[i].empty()) - warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); } if (vertexColour) From 1d934e3112423306ac3ae58ffb30412e88274b24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 04:46:28 -0700 Subject: [PATCH 0944/1483] Reduce some stdout spam --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e9db6d212a..3cd78a9338 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -13,7 +13,7 @@ MWMechanics::AiPackage * MWMechanics::AiWander::clone() const bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) { - std::cout << "AiWadner completed.\n"; + // Return completed return true; } diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 8402a5b4cd..1ff6fbbf1f 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -196,8 +196,6 @@ namespace MWScript MWMechanics::AiWander wanderPackage(range, duration, time, idleList); MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(wanderPackage); - - std::cout << "AiWander" << std::endl; } }; From 41ce5464c9088e8c79a6c91fdbb741cec1e51bb9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 05:00:19 -0700 Subject: [PATCH 0945/1483] Recognize NiBSAnimationNode as a record type And don't warn about animated nodes without textkeys --- components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 1 + components/nifogre/ogrenifloader.cpp | 11 ++++------- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index bf05e7576a..f97c506806 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -209,7 +209,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiNode", &construct , RC_NiNode }, { "AvoidNode", &construct , RC_NiNode }, { "NiBSParticleNode", &construct , RC_NiNode }, - { "NiBSAnimationNode", &construct , RC_NiNode }, + { "NiBSAnimationNode", &construct , RC_NiBSAnimationNode }, { "NiBillboardNode", &construct , RC_NiNode }, { "NiTriShape", &construct , RC_NiTriShape }, { "NiRotatingParticles", &construct , RC_NiRotatingParticles }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 3a3cd9b84a..361af3f64c 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -59,6 +59,7 @@ enum RecordType RC_NiMaterialColorController, RC_NiBSPArrayController, RC_NiParticleSystemController, + RC_NiBSAnimationNode, RC_NiLight, RC_NiTextureEffect, RC_NiVertWeightsExtraData, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 215462bac5..377fa94188 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -464,6 +464,10 @@ void loadResource(Ogre::Resource *resource) return; } + /* Animations without textkeys don't get Ogre::Animation objects. */ + if(!animroot) + return; + 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. @@ -486,13 +490,6 @@ void loadResource(Ogre::Resource *resource) return; } - if(!animroot) - { - warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ - skel->getName()+", but no text keys."); - return; - } - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); From f764f243d2e42ac5e63a9f44e49deee641a69226 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 06:44:34 -0700 Subject: [PATCH 0946/1483] Fix the particle quota --- components/nif/data.hpp | 4 +++- components/nifogre/ogrenifloader.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index c13495ff8b..0804b53ae2 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -165,6 +165,8 @@ public: class NiAutoNormalParticlesData : public ShapeData { public: + int numParticles; + float particleSize; int activeCount; @@ -176,7 +178,7 @@ public: ShapeData::read(nif); // Should always match the number of vertices - nif->getUShort(); + numParticles = nif->getUShort(); particleSize = nif->getFloat(); activeCount = nif->getUShort(); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 377fa94188..cadedbd709 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1274,7 +1274,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->activeCount); + partsys->setParticleQuota(particledata->numParticles); Nif::ControllerPtr ctrl = partnode->controller; while(!ctrl.empty()) From 95730cc127149317583a6051df4eea7b331f3628 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 06:53:08 -0700 Subject: [PATCH 0947/1483] Create entities and particle systems for hidden objects They're set as (in)visible as appropriate. --- components/nifogre/ogrenifloader.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index cadedbd709..3f20fbab30 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1375,7 +1375,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader ctrl = ctrl->next; } - if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden + if(node->recType == Nif::RC_NiTriShape) { const Nif::NiTriShape *shape = static_cast(node); @@ -1396,10 +1396,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader mesh->setAutoBuildEdgeLists(false); } - entities.mEntities.push_back(sceneMgr->createEntity(mesh)); + Ogre::Entity *entity = sceneMgr->createEntity(mesh); + entity->setVisible(!(flags&0x01)); + + entities.mEntities.push_back(entity); if(entities.mSkelBase) { - Ogre::Entity *entity = entities.mEntities.back(); if(entity->hasSkeleton()) entity->shareSkeletonInstanceWith(entities.mSkelBase); else @@ -1407,12 +1409,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - if((node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x01)) + if(node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) { Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); if(partsys != NULL) + { + partsys->setVisible(!(flags&0x01)); entities.mParticles.push_back(partsys); + } } const Nif::NiNode *ninode = dynamic_cast(node); From e0da2659729727481f7984983dc59551a27b076d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 08:15:12 -0700 Subject: [PATCH 0948/1483] Use accurate bone lookups for attaching objects NIFs don't requires nodes to have unique names, which means looking up a bone by name may get the wrong one. Instead, use a NifIndex:BoneHandle map to make sure we can get the proper bone from a given Nif::Node. --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3f20fbab30..06296ddeec 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -380,7 +380,6 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) return textkeys; } - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { Ogre::Bone *bone; @@ -389,6 +388,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro else bone = skel->createBone(); if(parent) parent->addChild(bone); + mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); @@ -439,6 +439,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro } } +// Lookup to retrieve an Ogre bone handle for a given Nif record index +std::map mNifToOgreHandleMap; typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -569,6 +571,20 @@ static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::stri return skelMgr.create(name, group, true, &sLoaders[name]); } +// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be +// used when the bone name is insufficient as this is a relatively slow lookup +static int lookupOgreBoneHandle(const std::string &nifname, int idx) +{ + LoaderMap::const_iterator loader = sLoaders.find(nifname); + if(loader != sLoaders.end()) + { + std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); + if(entry != loader->second.mNifToOgreHandleMap.end()) + return entry->second; + } + throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); +} + }; NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; @@ -1285,7 +1301,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader createParticleEmitterAffectors(partsys, partctrl); if(!partctrl->emitter.empty() && !partsys->isAttached()) - entitybase->attachObjectToBone(partctrl->emitter->name, partsys); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partctrl->emitter->recIndex); + Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); + entitybase->attachObjectToBone(trgtbone->getName(), partsys); + } } ctrl = ctrl->next; } @@ -1362,10 +1382,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - const Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); - if(!target) target = node; - - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(target->name); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::SharedPtr > srcval; /* Filled in later */ Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); @@ -1405,7 +1423,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(entity->hasSkeleton()) entity->shareSkeletonInstanceWith(entities.mSkelBase); else - entities.mSkelBase->attachObjectToBone(shape->name, entity); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); + entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + } } } From 0fb583e0659847a55d198cc5ecd07594bbc7768d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 17:35:36 +0200 Subject: [PATCH 0949/1483] added verifier for race record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/racecheck.cpp | 47 +++++++++++++++++++++++++++ apps/opencs/model/tools/racecheck.hpp | 29 +++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/racecheck.cpp create mode 100644 apps/opencs/model/tools/racecheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 07766507f7..0cf72b24c8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck ) diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp new file mode 100644 index 0000000000..50bb08a7c6 --- /dev/null +++ b/apps/opencs/model/tools/racecheck.cpp @@ -0,0 +1,47 @@ + +#include "racecheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) +: mRaces (races) +{} + +int CSMTools::RaceCheckStage::setup() +{ + return mRaces.getSize(); +} + +void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Race& race = mRaces.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId); + + // test for empty name and description + if (race.mName.empty()) + messages.push_back (id.toString() + "|" + race.mId + " has an empty name"); + + if (race.mDescription.empty()) + messages.push_back (id.toString() + "|" + race.mId + " has an empty description"); + + // test for positive height + if (race.mData.mHeight.mMale<=0) + messages.push_back (id.toString() + "|male " + race.mId + " has non-positive height"); + + if (race.mData.mHeight.mFemale<=0) + messages.push_back (id.toString() + "|female " + race.mId + " has non-positive height"); + + // test for non-negative weight + if (race.mData.mWeight.mMale<0) + messages.push_back (id.toString() + "|male " + race.mId + " has negative weight"); + + if (race.mData.mWeight.mFemale<0) + messages.push_back (id.toString() + "|female " + race.mId + " has negative weight"); + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/racecheck.hpp b/apps/opencs/model/tools/racecheck.hpp new file mode 100644 index 0000000000..e3f12599ba --- /dev/null +++ b/apps/opencs/model/tools/racecheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_RACECHECK_H +#define CSM_TOOLS_RACECHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that race records are internally consistent + class RaceCheckStage : public Stage + { + const CSMWorld::IdCollection& mRaces; + + public: + + RaceCheckStage (const CSMWorld::IdCollection& races); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index db45de43e5..5fb37514f0 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -15,6 +15,7 @@ #include "skillcheck.hpp" #include "classcheck.hpp" #include "factioncheck.hpp" +#include "racecheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -60,6 +61,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); + + mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); } return mVerifier; From 59f1d4b0476579146f358b827d4ca060f4b0a76f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 09:44:10 -0700 Subject: [PATCH 0950/1483] Add support for NiUVController on meshes --- apps/openmw/mwrender/animation.cpp | 5 +- components/nifogre/ogrenifloader.cpp | 120 ++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 00196c9d47..2b980320da 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -133,7 +133,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); for(size_t i = 0;i < mEntityList.mControllers.size();i++) - mEntityList.mControllers[i].setSource(ctrlval); + { + if(mEntityList.mControllers[i].getSource().isNull()) + mEntityList.mControllers[i].setSource(ctrlval); + } } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 06296ddeec..1e42fed37f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -139,6 +140,105 @@ public: }; }; +class UVController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::MaterialPtr mMaterial; + Nif::FloatKeyList mUTrans; + Nif::FloatKeyList mVTrans; + Nif::FloatKeyList mUScale; + Nif::FloatKeyList mVScale; + + static float lookupValue(float time, const Nif::FloatKeyList &keys) + { + Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); + for(;iter != keys.mKeys.end();iter++) + { + if(iter->mTime > time) + continue; + Nif::FloatKeyList::VecType::const_iterator next(iter+1); + if(next == keys.mKeys.end()) + return iter->mValue; + float a = (time-iter->mTime) / (next->mTime-iter->mTime); + return iter->mValue + ((next->mValue - iter->mValue)*a); + } + return 0.0f; + } + + public: + Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data) + : mMaterial(material) + , mUTrans(data->mKeyList[0]) + , mVTrans(data->mKeyList[1]) + , mUScale(data->mKeyList[2]) + , mVScale(data->mKeyList[3]) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 1.0f; + } + + virtual void setValue(Ogre::Real value) + { + float uTrans = lookupValue(value, mUTrans); + float vTrans = lookupValue(value, mVTrans); + float uScale = lookupValue(value, mUScale); + float vScale = lookupValue(value, mVScale); + if(uScale == 0.0f) uScale = 1.0f; + if(vScale == 0.0f) vScale = 1.0f; + + Ogre::Material::TechniqueIterator techs = mMaterial->getTechniqueIterator(); + while(techs.hasMoreElements()) + { + Ogre::Technique *tech = techs.getNext(); + Ogre::Technique::PassIterator passes = tech->getPassIterator(); + while(passes.hasMoreElements()) + { + Ogre::Pass *pass = passes.getNext(); + Ogre::TextureUnitState *tex = pass->getTextureUnitState(0); + tex->setTextureScroll(uTrans, vTrans); + tex->setTextureScale(uScale, vScale); + } + } + } + }; + + class Function : public Ogre::ControllerFunction + { + private: + float mFrequency; + float mPhase; + float mStartTime; + float mStopTime; + + public: + Function(const Nif::NiUVController *ctrl) + : Ogre::ControllerFunction(false) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } + + virtual Ogre::Real calculate(Ogre::Real value) + { + mDeltaCount += value; + mDeltaCount = std::fmod(mDeltaCount+(value*mFrequency) - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + }; +}; + // Helper class that computes the bounding box and of a mesh class BoundsFinder @@ -409,7 +509,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; @@ -1429,6 +1530,23 @@ class NIFMeshLoader : Ogre::ManualResourceLoader entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } } + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); + + const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); + Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); + + entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } } if(node->recType == Nif::RC_NiAutoNormalParticles || From e50b6b1cfe9f3738909e8857b8f67bb7b282ddd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 09:45:26 -0700 Subject: [PATCH 0951/1483] Apply texture matrix 0 in the object shader --- files/materials/objects.shader | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index d0e8173733..4868cf98d1 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -36,6 +36,8 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shUniform(float4x4, textureMatrix0) @shAutoConstant(textureMatrix0, texture_matrix, 0) + #if (VIEWPROJ_FIX) || (SHADOWS) shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) #endif @@ -118,7 +120,7 @@ { shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV.xy = uv0; + UV.xy = shMatrixMult (textureMatrix0, float4(uv0,0,1)).xy; #if SECOND_UV_SET UV.zw = uv1; #endif From ebcb4c66c3adc94217bb912f48789ccde6682668 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 10:17:09 -0700 Subject: [PATCH 0952/1483] Properly read and use the NIF root record list --- components/nif/niffile.cpp | 18 +++++++++++------- components/nif/niffile.hpp | 14 +++++++++++++- components/nifbullet/bulletnifloader.cpp | 11 +++++------ components/nifogre/ogrenifloader.cpp | 20 ++++++++++---------- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index f97c506806..44eae2953d 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -345,14 +345,18 @@ void NIFFile::parse() } } - /* After the data, the nif contains an int N and then a list of N - ints following it. This might be a list of the root nodes in the - tree, but for the moment we ignore it. - */ + size_t rootNum = nif.getUInt(); + roots.resize(rootNum); - // Once parsing is done, do post-processing. - for(size_t i=0; ipost(this); + for(size_t i = 0;i < rootNum;i++) + { + intptr_t idx = nif.getInt(); + roots[i] = ((idx >= 0) ? records.at(idx) : NULL); + } + + // Once parsing is done, do post-processing. + for(size_t i=0; ipost(this); } /// \todo move to the write cpp file diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index ed11bdd7cb..6e629772e6 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -66,6 +66,9 @@ class NIFFile /// Record list std::vector records; + /// Root list + std::vector roots; + /// Parse the file void parse(); @@ -115,9 +118,18 @@ public: assert(res != NULL); return res; } - /// Number of records size_t numRecords() { return records.size(); } + + /// Get a given root + Record *getRoot(size_t index=0) + { + Record *res = roots.at(index); + assert(res != NULL); + return res; + } + /// Number of roots + size_t numRoots() { return roots.size(); } }; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 08625ee9cb..6bd43f6e35 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -91,21 +91,20 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) // likely a sign of incomplete code rather than faulty input. Nif::NIFFile::ptr pnif (Nif::NIFFile::create (resourceName.substr(0, resourceName.length()-7))); Nif::NIFFile & nif = *pnif.get (); - if (nif.numRecords() < 1) + if (nif.numRoots() < 1) { - warn("Found no records in NIF."); + warn("Found no root nodes in NIF."); return; } - // The first record is assumed to be the root node - Nif::Record *r = nif.getRecord(0); + Nif::Record *r = nif.getRoot(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."); + warn("First root in file was not a node, but a " + + r->recName + ". Skipping file."); return; } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 1e42fed37f..830e85cdef 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -553,7 +553,7 @@ void loadResource(Ogre::Resource *resource) OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); - const Nif::Node *node = static_cast(nif->getRecord(0)); + const Nif::Node *node = static_cast(nif->getRoot(0)); std::vector ctrls; Ogre::Bone *animroot = NULL; @@ -1441,7 +1441,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader return; } - const Nif::Node *node = dynamic_cast(nif->getRecord(0)); + const Nif::Node *node = dynamic_cast(nif->getRecord(mShapeIndex)); findTriShape(mesh, node); } @@ -1603,21 +1603,21 @@ public: { Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) + if(nif.numRoots() < 1) { - nif.warn("Found no NIF records in "+name+"."); + nif.warn("Found no root nodes in "+name+"."); return; } // The first record is assumed to be the root node - const Nif::Record *r = nif.getRecord(0); + const Nif::Record *r = nif.getRoot(0); assert(r != NULL); const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); + nif.warn("First root in "+name+" was not a node, but a "+ + r->recName+"."); return; } @@ -1722,14 +1722,14 @@ Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group return skel; Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); - if(nif->numRecords() < 1) + if(nif->numRoots() < 1) { - nif->warn("Found no NIF records in "+name+"."); + nif->warn("Found no root nodes in "+name+"."); return skel; } // The first record is assumed to be the root node - const Nif::Record *r = nif->getRecord(0); + const Nif::Record *r = nif->getRoot(0); assert(r != NULL); const Nif::Node *node = dynamic_cast(r); From 9bc3945f406f3cd252d3a05cf00dc175c7fea17e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 19:20:46 +0200 Subject: [PATCH 0953/1483] multiple fixes to UniversalId constructor --- apps/opencs/model/world/universalid.cpp | 69 ++++++++++++------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 2e5e6a0a0a..5c7547d71d 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -55,44 +55,41 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId) { std::string type = universalId.substr (0, index); - if (index==std::string::npos) - { - for (int i=0; sNoArg[i].mName; ++i) - if (type==sNoArg[i].mName) - { - mArgumentType = ArgumentType_None; - mType = sNoArg[i].mType; - mClass = sNoArg[i].mClass; + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mName) + { + mArgumentType = ArgumentType_Id; + mType = sIdArg[i].mType; + mClass = sIdArg[i].mClass; + mId = universalId.substr (index+2); + return; + } + + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mName) + { + mArgumentType = ArgumentType_Index; + mType = sIndexArg[i].mType; + mClass = sIndexArg[i].mClass; + + std::istringstream stream (universalId.substr (index+2)); + + if (stream >> mIndex) return; - } - } - else - { - for (int i=0; sIdArg[i].mName; ++i) - if (type==sIdArg[i].mName) - { - mArgumentType = ArgumentType_Id; - mType = sIdArg[i].mType; - mClass = sIdArg[i].mClass; - mId = universalId.substr (0, index); - return; - } - for (int i=0; sIndexArg[i].mName; ++i) - if (type==sIndexArg[i].mName) - { - mArgumentType = ArgumentType_Index; - mType = sIndexArg[i].mType; - mClass = sIndexArg[i].mClass; - - std::istringstream stream (universalId.substr (0, index)); - - if (stream >> mIndex) - return; - - break; - } - } + break; + } + } + else + { + for (int i=0; sNoArg[i].mName; ++i) + if (universalId==sNoArg[i].mName) + { + mArgumentType = ArgumentType_None; + mType = sNoArg[i].mType; + mClass = sNoArg[i].mClass; + return; + } } throw std::runtime_error ("invalid UniversalId: " + universalId); From 98e7b3fd938edbe334de7bfc36aa2d721f6a3b50 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 19:20:59 +0200 Subject: [PATCH 0954/1483] check for at least one playable race --- apps/opencs/model/tools/racecheck.cpp | 41 ++++++++++++++++++++------- apps/opencs/model/tools/racecheck.hpp | 5 ++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 50bb08a7c6..1e7a4cab45 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -7,16 +7,7 @@ #include "../world/universalid.hpp" -CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) -: mRaces (races) -{} - -int CSMTools::RaceCheckStage::setup() -{ - return mRaces.getSize(); -} - -void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector& messages) { const ESM::Race& race = mRaces.getRecord (stage).get(); @@ -43,5 +34,35 @@ void CSMTools::RaceCheckStage::perform (int stage, std::vector& mes if (race.mData.mWeight.mFemale<0) messages.push_back (id.toString() + "|female " + race.mId + " has negative weight"); + // remember playable flag + if (race.mData.mFlags & 0x1) + mPlayable = true; + /// \todo check data members that can't be edited in the table view +} + +void CSMTools::RaceCheckStage::performFinal (std::vector& messages) +{ + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races); + + if (!mPlayable) + messages.push_back (id.toString() + "|No playable race"); +} + +CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) +: mRaces (races), mPlayable (false) +{} + +int CSMTools::RaceCheckStage::setup() +{ + mPlayable = false; + return mRaces.getSize()+1; +} + +void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +{ + if (stage==mRaces.getSize()) + performFinal (messages); + else + performPerRecord (stage, messages); } \ No newline at end of file diff --git a/apps/opencs/model/tools/racecheck.hpp b/apps/opencs/model/tools/racecheck.hpp index e3f12599ba..155f799021 100644 --- a/apps/opencs/model/tools/racecheck.hpp +++ b/apps/opencs/model/tools/racecheck.hpp @@ -13,6 +13,11 @@ namespace CSMTools class RaceCheckStage : public Stage { const CSMWorld::IdCollection& mRaces; + bool mPlayable; + + void performPerRecord (int stage, std::vector& messages); + + void performFinal (std::vector& messages); public: From 1f3df4df0f9ccbdb452ea7e88de4b7f02c417a59 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Apr 2013 19:25:29 +0200 Subject: [PATCH 0955/1483] Perform a sanity check on count arguments --- apps/openmw/mwscript/miscextensions.cpp | 7 +++++++ apps/openmw/mwscript/transformationextensions.cpp | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index f329e30d90..489f6bd3db 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -399,6 +399,13 @@ namespace MWScript Interpreter::Type_Integer amount = runtime[0].mInteger; runtime.pop(); + if (amount<0) + throw std::runtime_error ("amount must be non-negative"); + + // no-op + if (amount == 0) + return; + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 97dc6d7188..49688efb5d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -460,6 +460,13 @@ namespace MWScript Interpreter::Type_Integer direction = runtime[0].mInteger; runtime.pop(); + if (count<0) + throw std::runtime_error ("count must be non-negative"); + + // no-op + if (count == 0) + return; + ESM::Position ipos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition(); Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); @@ -503,6 +510,13 @@ namespace MWScript Interpreter::Type_Integer direction = runtime[0].mInteger; runtime.pop(); + if (count<0) + throw std::runtime_error ("count must be non-negative"); + + // no-op + if (count == 0) + return; + ESM::Position ipos = me.getRefData().getPosition(); Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); From c28399112637417ddf66a9b65ebec4409227d16e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 10:33:07 -0700 Subject: [PATCH 0956/1483] Remove an unneeded method --- components/nifogre/ogrenifloader.cpp | 30 +++------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 830e85cdef..5206ef8344 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1070,7 +1070,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) + void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -1295,30 +1295,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node) - { - if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) - { - handleNiTriShape(mesh, dynamic_cast(node)); - return true; - } - - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const 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; @@ -1441,8 +1417,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader return; } - const Nif::Node *node = dynamic_cast(nif->getRecord(mShapeIndex)); - findTriShape(mesh, node); + const Nif::Record *record = nif->getRecord(mShapeIndex); + createSubMesh(mesh, dynamic_cast(record)); } void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) From 6b151be3f427ea361e03e9830236642b41721aac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 11:26:51 -0700 Subject: [PATCH 0957/1483] Create particle systems even when MRK was specified --- components/nifogre/ogrenifloader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 5206ef8344..6a7c3c6dbf 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1444,9 +1444,9 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // affecting the entire subtree of this obj if(sd->string == "MRK") { - // Marker objects. These are only visible in the + // Marker objects. These meshes are only visible in the // editor. - return; + flags |= 0x80000000; } } e = e->extra; @@ -1470,7 +1470,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader ctrl = ctrl->next; } - if(node->recType == Nif::RC_NiTriShape) + if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { const Nif::NiTriShape *shape = static_cast(node); From 8bf569d58ab00c1ef804b802e3bec5bc358032f0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:21:10 +0200 Subject: [PATCH 0958/1483] added basic sound table --- apps/opencs/model/world/data.cpp | 15 +++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadsoun.cpp | 8 ++++++++ components/esm/loadsoun.hpp | 3 +++ 9 files changed, 49 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fb835b986a..b6fb437695 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -77,12 +77,16 @@ CSMWorld::Data::Data() mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); + mSounds.addColumn (new StringIdColumn); + mSounds.addColumn (new RecordStateColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); + addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); } CSMWorld::Data::~Data() @@ -151,6 +155,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getRaces() return mRaces; } +const CSMWorld::IdCollection& CSMWorld::Data::getSounds() const +{ + return mSounds; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSounds() +{ + return mSounds; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -191,6 +205,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_CLAS: mClasses.load (reader, base); break; case ESM::REC_FACT: mFactions.load (reader, base); break; case ESM::REC_RACE: mRaces.load (reader, base); break; + case ESM::REC_SOUN: mSounds.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 6b729728f5..320480e639 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -28,6 +29,7 @@ namespace CSMWorld IdCollection mClasses; IdCollection mFactions; IdCollection mRaces; + IdCollection mSounds; std::vector mModels; std::map mModelIndex; @@ -68,6 +70,10 @@ namespace CSMWorld IdCollection& getRaces(); + const IdCollection& getSounds() const; + + IdCollection& getSounds(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 5c7547d71d..7bdc15c8c7 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -23,6 +23,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -35,6 +36,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 2213e15f31..a21d67fcd8 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -45,7 +45,9 @@ namespace CSMWorld Type_Factions, Type_Faction, Type_Races, - Type_Race + Type_Race, + Type_Sounds, + Type_Sound }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index e12929cf2e..611690ca65 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -105,6 +105,10 @@ void CSVDoc::View::setupWorldMenu() QAction *races = new QAction (tr ("Races"), this); connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView())); world->addAction (races); + + QAction *sounds = new QAction (tr ("Sounds"), this); + connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); + world->addAction (sounds); } void CSVDoc::View::setupUi() @@ -280,6 +284,11 @@ void CSVDoc::View::addRacesSubView() addSubView (CSMWorld::UniversalId::Type_Races); } +void CSVDoc::View::addSoundsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Sounds); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 4132d73b20..e8e716b706 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -123,6 +123,8 @@ namespace CSVDoc void addFactionsSubView(); void addRacesSubView(); + + void addSoundsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index d5ba273776..3ba950f879 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -20,6 +20,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Classes, CSMWorld::UniversalId::Type_Factions, CSMWorld::UniversalId::Type_Races, + CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 87a08d2d3a..75d4bc8de6 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -23,4 +23,12 @@ void Sound::save(ESMWriter &esm) esm.writeHNT("DATA", mData, 3); } + void Sound::blank() + { + mSound.clear(); + + mData.mVolume = 128; + mData.mMinRange = 0; + mData.mMaxRange = 256; + } } diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 8f59f690a1..f8e38ac092 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -21,6 +21,9 @@ struct Sound void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From ca289a317c579c44b83132cf2bb5b471a8d5b979 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 12:26:58 -0700 Subject: [PATCH 0959/1483] Separate the UVController function out and make it generic Also fix a timing bug in it. --- components/nifogre/ogrenifloader.cpp | 60 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6a7c3c6dbf..dfdec0bfa6 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -66,6 +66,36 @@ namespace NifOgre { // FIXME: Should not be here. +class DefaultFunction : public Ogre::ControllerFunction +{ +private: + float mFrequency; + float mPhase; + float mStartTime; + float mStopTime; + +public: + DefaultFunction(const Nif::Controller *ctrl) + : Ogre::ControllerFunction(false) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } + + virtual Ogre::Real calculate(Ogre::Real value) + { + mDeltaCount += value*mFrequency; + mDeltaCount = std::fmod(mDeltaCount - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } +}; + class VisController { public: @@ -208,35 +238,7 @@ public: } }; - class Function : public Ogre::ControllerFunction - { - private: - float mFrequency; - float mPhase; - float mStartTime; - float mStopTime; - - public: - Function(const Nif::NiUVController *ctrl) - : Ogre::ControllerFunction(false) - , mFrequency(ctrl->frequency) - , mPhase(ctrl->phase) - , mStartTime(ctrl->timeStart) - , mStopTime(ctrl->timeStop) - { - mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); - } - - virtual Ogre::Real calculate(Ogre::Real value) - { - mDeltaCount += value; - mDeltaCount = std::fmod(mDeltaCount+(value*mFrequency) - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; - } - }; + typedef DefaultFunction Function; }; From dd5940b395a5439aa08cd080a0afb3f585fd99ae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:40:03 +0200 Subject: [PATCH 0960/1483] added sound parameter columns to sonud table --- apps/opencs/model/world/columns.hpp | 60 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++ 2 files changed, 63 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index f65f212da1..0416287ba0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -506,6 +506,66 @@ namespace CSMWorld return true; } }; + + template + struct SoundParamColumn : public Column + { + enum Type + { + Type_Volume, + Type_MinRange, + Type_MaxRange + }; + + Type mType; + + SoundParamColumn (Type type) + : Column ( + type==Type_Volume ? "Volume" : (type==Type_MinRange ? "Min Range" : "Max Range"), + ColumnBase::Display_Integer), + mType (type) + {} + + virtual QVariant get (const Record& record) const + { + int value = 0; + + switch (mType) + { + case Type_Volume: value = record.get().mData.mVolume; break; + case Type_MinRange: value = record.get().mData.mMinRange; break; + case Type_MaxRange: value = record.get().mData.mMaxRange; break; + } + + return value; + } + + virtual void set (Record& record, const QVariant& data) + { + int value = data.toInt(); + + if (value<0) + value = 0; + else if (value>255) + value = 255; + + ESXRecordT record2 = record.get(); + + switch (mType) + { + case Type_Volume: record2.mData.mVolume = static_cast (value); break; + case Type_MinRange: record2.mData.mMinRange = static_cast (value); break; + case Type_MaxRange: record2.mData.mMaxRange = static_cast (value); break; + } + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b6fb437695..afa70cdc17 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -79,6 +79,9 @@ CSMWorld::Data::Data() mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 63cbf7ddeb3a00d89dc43850219bfa7e86dcbd6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 12:41:40 -0700 Subject: [PATCH 0961/1483] Specify a default return for failed lookups --- components/nifogre/ogrenifloader.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index dfdec0bfa6..d89d0d30a5 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -182,7 +182,7 @@ public: Nif::FloatKeyList mUScale; Nif::FloatKeyList mVScale; - static float lookupValue(float time, const Nif::FloatKeyList &keys) + static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) { Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); for(;iter != keys.mKeys.end();iter++) @@ -195,7 +195,7 @@ public: float a = (time-iter->mTime) / (next->mTime-iter->mTime); return iter->mValue + ((next->mValue - iter->mValue)*a); } - return 0.0f; + return def; } public: @@ -215,12 +215,10 @@ public: virtual void setValue(Ogre::Real value) { - float uTrans = lookupValue(value, mUTrans); - float vTrans = lookupValue(value, mVTrans); - float uScale = lookupValue(value, mUScale); - float vScale = lookupValue(value, mVScale); - if(uScale == 0.0f) uScale = 1.0f; - if(vScale == 0.0f) vScale = 1.0f; + float uTrans = lookupValue(mUTrans, value, 0.0f); + float vTrans = lookupValue(mVTrans, value, 0.0f); + float uScale = lookupValue(mUScale, value, 1.0f); + float vScale = lookupValue(mVScale, value, 1.0f); Ogre::Material::TechniqueIterator techs = mMaterial->getTechniqueIterator(); while(techs.hasMoreElements()) From 50b58b2ead2ae4b4db3ad9936f9a781592f55823 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:43:05 +0200 Subject: [PATCH 0962/1483] added sound file column to sound table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 0416287ba0..75dfe15c27 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -566,6 +566,31 @@ namespace CSMWorld return true; } }; + + template + struct SoundFileColumn : public Column + { + SoundFileColumn() : Column ("Sound File", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mSound.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mSound = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index afa70cdc17..69109bd743 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -82,6 +82,7 @@ CSMWorld::Data::Data() mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); + mSounds.addColumn (new SoundFileColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From e2c6458adb3509388c178f421d08b73787119619 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:48:52 +0200 Subject: [PATCH 0963/1483] added verifier for sound records --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/soundcheck.cpp | 29 ++++++++++++++++++++++++++ apps/opencs/model/tools/soundcheck.hpp | 29 ++++++++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/soundcheck.cpp create mode 100644 apps/opencs/model/tools/soundcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0cf72b24c8..ffd4c7f1ea 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck racecheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck ) diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp new file mode 100644 index 0000000000..52834e6594 --- /dev/null +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -0,0 +1,29 @@ + +#include "soundcheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection& sounds) +: mSounds (sounds) +{} + +int CSMTools::SoundCheckStage::setup() +{ + return mSounds.getSize(); +} + +void CSMTools::SoundCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Sound& sound = mSounds.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId); + + if (sound.mData.mMinRange>sound.mData.mMaxRange) + messages.push_back (id.toString() + "|Maximum range larger than minimum range"); + + /// \todo check, if the sound file exists +} \ No newline at end of file diff --git a/apps/opencs/model/tools/soundcheck.hpp b/apps/opencs/model/tools/soundcheck.hpp new file mode 100644 index 0000000000..a309763a12 --- /dev/null +++ b/apps/opencs/model/tools/soundcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SOUNDCHECK_H +#define CSM_TOOLS_SOUNDCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that sound records are internally consistent + class SoundCheckStage : public Stage + { + const CSMWorld::IdCollection& mSounds; + + public: + + SoundCheckStage (const CSMWorld::IdCollection& sounds); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 5fb37514f0..4003bc8840 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -16,6 +16,7 @@ #include "classcheck.hpp" #include "factioncheck.hpp" #include "racecheck.hpp" +#include "soundcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -63,6 +64,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); + + mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); } return mVerifier; From ec7a8f1add42914684290b4e99bbc8d8f054d586 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:58:28 +0200 Subject: [PATCH 0964/1483] small fix --- components/esm/loadsoun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 75d4bc8de6..07af2b5e91 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -29,6 +29,6 @@ void Sound::save(ESMWriter &esm) mData.mVolume = 128; mData.mMinRange = 0; - mData.mMaxRange = 256; + mData.mMaxRange = 255; } } From 4daaa4030d7434b50a2f835f44329a217e9be357 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 00:12:04 +0200 Subject: [PATCH 0965/1483] Added shader based MyGUI render manager to allow using Ogre's next generation render systems. --- files/CMakeLists.txt | 3 + files/materials/mygui.mat | 25 ++ files/materials/mygui.shader | 45 +++ files/materials/mygui.shaderset | 15 + libs/openengine/gui/manager.cpp | 537 +++++++++++++++++++++++++++++++- libs/openengine/gui/manager.hpp | 4 +- 6 files changed, 625 insertions(+), 4 deletions(-) create mode 100644 files/materials/mygui.mat create mode 100644 files/materials/mygui.shader create mode 100644 files/materials/mygui.shaderset diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9e65b516b7..9b2325744e 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -44,6 +44,9 @@ set(MATERIAL_FILES watersim_common.h watersim.mat watersim.shaderset + mygui.mat + mygui.shader + mygui.shaderset ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/mygui.mat b/files/materials/mygui.mat new file mode 100644 index 0000000000..78cba3f897 --- /dev/null +++ b/files/materials/mygui.mat @@ -0,0 +1,25 @@ +material MyGUI/NoTexture +{ + pass + { + vertex_program mygui_vertex + fragment_program mygui_fragment + shader_properties + { + has_texture false + } + } +} + +material MyGUI/OneTexture +{ + pass + { + vertex_program mygui_vertex + fragment_program mygui_fragment + shader_properties + { + has_texture true + } + } +} diff --git a/files/materials/mygui.shader b/files/materials/mygui.shader new file mode 100644 index 0000000000..014558d972 --- /dev/null +++ b/files/materials/mygui.shader @@ -0,0 +1,45 @@ +#include "core.h" + +#define TEXTURE @shPropertyBool(has_texture) + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM +#if TEXTURE + shVertexInput(float2, uv0) + shOutput(float2, UV) +#endif + shColourInput(float4) + shOutput(float4, colourPassthrough) + + SH_START_PROGRAM + { + shOutputPosition = float4(shInputPosition.xyz, 1.f); +#if TEXTURE + UV.xy = uv0; +#endif + colourPassthrough = colour; + } + +#else + + + SH_BEGIN_PROGRAM + +#if TEXTURE + shSampler2D(diffuseMap) + shInput(float2, UV) +#endif + + shInput(float4, colourPassthrough) + + SH_START_PROGRAM + { +#if TEXTURE + shOutputColour(0) = shSample(diffuseMap, UV.xy) * colourPassthrough; +#else + shOutputColour(0) = colourPassthrough; +#endif + } + +#endif diff --git a/files/materials/mygui.shaderset b/files/materials/mygui.shaderset new file mode 100644 index 0000000000..980cd4caf4 --- /dev/null +++ b/files/materials/mygui.shaderset @@ -0,0 +1,15 @@ +shader_set mygui_vertex +{ + source mygui.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_3_0 vs_2_0 +} + +shader_set mygui_fragment +{ + source mygui.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index c9b5614008..f9117586fe 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -2,11 +2,18 @@ #include #include +#include #include +#include +#include + using namespace OEngine::GUI; +namespace MyGUI +{ + /* * As of MyGUI 3.2.0, MyGUI::OgreDataManager::isDataExist is unnecessarily complex * this override fixes the resulting performance issue. @@ -20,6 +27,532 @@ public: } }; + +/* + * As of MyGUI 3.2.0, rendering with shaders is not supported. + * We definitely need this though to run in GL3 core / DX11 at all. + * To make matters worse, subclassing OgreRenderManager doesn't seem to be possible here. :/ + */ +class ShaderBasedRenderManager : public RenderManager, + public IRenderTarget, + public Ogre::WindowEventListener, + public Ogre::RenderQueueListener, + public Ogre::RenderSystem::Listener +{ + // флаг для обновления всех и вся + bool mUpdate; + + IntSize mViewSize; + + Ogre::SceneManager* mSceneManager; + + VertexColourType mVertexFormat; + + // окно, на которое мы подписываемся для изменения размеров + Ogre::RenderWindow* mWindow; + + // вьюпорт, с которым работает система + unsigned short mActiveViewport; + + Ogre::RenderSystem* mRenderSystem; + Ogre::TextureUnitState::UVWAddressingMode mTextureAddressMode; + Ogre::LayerBlendModeEx mColorBlendMode, mAlphaBlendMode; + + RenderTargetInfo mInfo; + + typedef std::map MapTexture; + MapTexture mTextures; + + bool mIsInitialise; + bool mManualRender; + size_t mCountBatch; + + // ADDED + Ogre::GpuProgram* mVertexProgramNoTexture; + Ogre::GpuProgram* mVertexProgramOneTexture; + Ogre::GpuProgram* mFragmentProgramNoTexture; + Ogre::GpuProgram* mFragmentProgramOneTexture; + +public: + ShaderBasedRenderManager& getInstance() + { + return *getInstancePtr(); + } + ShaderBasedRenderManager* getInstancePtr() + { + return static_cast(RenderManager::getInstancePtr()); + } + + ShaderBasedRenderManager() : + mUpdate(false), + mSceneManager(nullptr), + mWindow(nullptr), + mActiveViewport(0), + mRenderSystem(nullptr), + mIsInitialise(false), + mManualRender(false), + mCountBatch(0) + { + } + + void initialise(Ogre::RenderWindow* _window, Ogre::SceneManager* _scene) + { + MYGUI_PLATFORM_ASSERT(!mIsInitialise, getClassTypeName() << " initialised twice"); + MYGUI_PLATFORM_LOG(Info, "* Initialise: " << getClassTypeName()); + + mColorBlendMode.blendType = Ogre::LBT_COLOUR; + mColorBlendMode.source1 = Ogre::LBS_TEXTURE; + mColorBlendMode.source2 = Ogre::LBS_DIFFUSE; + mColorBlendMode.operation = Ogre::LBX_MODULATE; + + mAlphaBlendMode.blendType = Ogre::LBT_ALPHA; + mAlphaBlendMode.source1 = Ogre::LBS_TEXTURE; + mAlphaBlendMode.source2 = Ogre::LBS_DIFFUSE; + mAlphaBlendMode.operation = Ogre::LBX_MODULATE; + + mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; + mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP; + mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP; + + mSceneManager = nullptr; + mWindow = nullptr; + mUpdate = false; + mRenderSystem = nullptr; + mActiveViewport = 0; + + Ogre::Root* root = Ogre::Root::getSingletonPtr(); + if (root != nullptr) + setRenderSystem(root->getRenderSystem()); + setRenderWindow(_window); + setSceneManager(_scene); + + // ADDED + sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); + mVertexProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getVertexProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); + mVertexProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getVertexProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); + mFragmentProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getFragmentProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); + mFragmentProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getFragmentProgram()->_getBindingDelegate(); + + + + MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully initialized"); + mIsInitialise = true; + } + + void shutdown() + { + MYGUI_PLATFORM_ASSERT(mIsInitialise, getClassTypeName() << " is not initialised"); + MYGUI_PLATFORM_LOG(Info, "* Shutdown: " << getClassTypeName()); + + destroyAllResources(); + + setSceneManager(nullptr); + setRenderWindow(nullptr); + setRenderSystem(nullptr); + + MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully shutdown"); + mIsInitialise = false; + } + + void setRenderSystem(Ogre::RenderSystem* _render) + { + // отписываемся + if (mRenderSystem != nullptr) + { + mRenderSystem->removeListener(this); + mRenderSystem = nullptr; + } + + mRenderSystem = _render; + + // подписываемся на рендер евент + if (mRenderSystem != nullptr) + { + mRenderSystem->addListener(this); + + // формат цвета в вершинах + Ogre::VertexElementType vertex_type = mRenderSystem->getColourVertexElementType(); + if (vertex_type == Ogre::VET_COLOUR_ARGB) + mVertexFormat = VertexColourType::ColourARGB; + else if (vertex_type == Ogre::VET_COLOUR_ABGR) + mVertexFormat = VertexColourType::ColourABGR; + + updateRenderInfo(); + } + } + + Ogre::RenderSystem* getRenderSystem() + { + return mRenderSystem; + } + + void setRenderWindow(Ogre::RenderWindow* _window) + { + // отписываемся + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); + mWindow = nullptr; + } + + mWindow = _window; + + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); + windowResized(mWindow); + } + } + + void setSceneManager(Ogre::SceneManager* _scene) + { + if (nullptr != mSceneManager) + { + mSceneManager->removeRenderQueueListener(this); + mSceneManager = nullptr; + } + + mSceneManager = _scene; + + if (nullptr != mSceneManager) + { + mSceneManager->addRenderQueueListener(this); + } + } + + void setActiveViewport(unsigned short _num) + { + mActiveViewport = _num; + + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); + + // рассылка обновлений + windowResized(mWindow); + } + } + + void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation) + { + Gui* gui = Gui::getInstancePtr(); + if (gui == nullptr) + return; + + if (Ogre::RENDER_QUEUE_OVERLAY != queueGroupId) + return; + + Ogre::Viewport* viewport = mSceneManager->getCurrentViewport(); + if (nullptr == viewport + || !viewport->getOverlaysEnabled()) + return; + + if (mWindow->getNumViewports() <= mActiveViewport + || viewport != mWindow->getViewport(mActiveViewport)) + return; + + mCountBatch = 0; + + static Timer timer; + static unsigned long last_time = timer.getMilliseconds(); + unsigned long now_time = timer.getMilliseconds(); + unsigned long time = now_time - last_time; + + onFrameEvent((float)((double)(time) / (double)1000)); + + last_time = now_time; + + //begin(); + setManualRender(true); + onRenderToTarget(this, mUpdate); + //end(); + + // сбрасываем флаг + mUpdate = false; + } + + void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation) + { + } + + void eventOccurred(const Ogre::String& eventName, const Ogre::NameValuePairList* parameters) + { + if (eventName == "DeviceLost") + { + } + else if (eventName == "DeviceRestored") + { + // обновить всех + mUpdate = true; + } + } + + IVertexBuffer* createVertexBuffer() + { + return new OgreVertexBuffer(); + } + + void destroyVertexBuffer(IVertexBuffer* _buffer) + { + delete _buffer; + } + + // для оповещений об изменении окна рендера + void windowResized(Ogre::RenderWindow* _window) + { + if (_window->getNumViewports() > mActiveViewport) + { + Ogre::Viewport* port = _window->getViewport(mActiveViewport); +#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 + Ogre::OrientationMode orient = port->getOrientationMode(); + if (orient == Ogre::OR_DEGREE_90 || orient == Ogre::OR_DEGREE_270) + mViewSize.set(port->getActualHeight(), port->getActualWidth()); + else + mViewSize.set(port->getActualWidth(), port->getActualHeight()); +#else + mViewSize.set(port->getActualWidth(), port->getActualHeight()); +#endif + + // обновить всех + mUpdate = true; + + updateRenderInfo(); + + onResizeView(mViewSize); + } + } + + void updateRenderInfo() + { + if (mRenderSystem != nullptr) + { + mInfo.maximumDepth = mRenderSystem->getMaximumDepthInputValue(); + mInfo.hOffset = mRenderSystem->getHorizontalTexelOffset() / float(mViewSize.width); + mInfo.vOffset = mRenderSystem->getVerticalTexelOffset() / float(mViewSize.height); + mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); + mInfo.pixScaleX = 1.0f / float(mViewSize.width); + mInfo.pixScaleY = 1.0f / float(mViewSize.height); + } + } + + void doRender(IVertexBuffer* _buffer, ITexture* _texture, size_t _count) + { + if (getManualRender()) + { + begin(); + setManualRender(false); + } + + // ADDED + + if (_texture) + { + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramOneTexture); + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramOneTexture); + } + else + { + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramNoTexture); + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramNoTexture); + } + + if (_texture) + { + OgreTexture* texture = static_cast(_texture); + Ogre::TexturePtr texture_ptr = texture->getOgreTexture(); + if (!texture_ptr.isNull()) + { + mRenderSystem->_setTexture(0, true, texture_ptr); + mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); + } + } + + OgreVertexBuffer* buffer = static_cast(_buffer); + Ogre::RenderOperation* operation = buffer->getRenderOperation(); + operation->vertexData->vertexCount = _count; + + mRenderSystem->_render(*operation); + + ++ mCountBatch; + } + + void begin() + { + // set-up matrices + mRenderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY); + mRenderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY); + +#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 + Ogre::OrientationMode orient = mWindow->getViewport(mActiveViewport)->getOrientationMode(); + mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY * Ogre::Quaternion(Ogre::Degree(orient * 90.f), Ogre::Vector3::UNIT_Z)); +#else + mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY); +#endif + + // initialise render settings + mRenderSystem->setLightingEnabled(false); + mRenderSystem->_setDepthBufferParams(false, false); + mRenderSystem->_setDepthBias(0, 0); + mRenderSystem->_setCullingMode(Ogre::CULL_NONE); + mRenderSystem->_setFog(Ogre::FOG_NONE); + mRenderSystem->_setColourBufferWriteEnabled(true, true, true, true); + mRenderSystem->unbindGpuProgram(Ogre::GPT_FRAGMENT_PROGRAM); + mRenderSystem->unbindGpuProgram(Ogre::GPT_VERTEX_PROGRAM); + mRenderSystem->setShadingType(Ogre::SO_GOURAUD); + + // initialise texture settings + mRenderSystem->_setTextureCoordCalculation(0, Ogre::TEXCALC_NONE); + mRenderSystem->_setTextureCoordSet(0, 0); + mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); + mRenderSystem->_setTextureAddressingMode(0, mTextureAddressMode); + mRenderSystem->_setTextureMatrix(0, Ogre::Matrix4::IDENTITY); +#if OGRE_VERSION < MYGUI_DEFINE_VERSION(1, 6, 0) + mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0); +#else + mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0, false); +#endif + mRenderSystem->_setTextureBlendMode(0, mColorBlendMode); + mRenderSystem->_setTextureBlendMode(0, mAlphaBlendMode); + mRenderSystem->_disableTextureUnitsFrom(1); + + // enable alpha blending + mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); + + // always use wireframe + // TODO: add option to enable wireframe mode in platform + mRenderSystem->_setPolygonMode(Ogre::PM_SOLID); + } + + void end() + { + } + + ITexture* createTexture(const std::string& _name) + { + MapTexture::const_iterator item = mTextures.find(_name); + MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '" << _name << "' already exist"); + + OgreTexture* texture = new OgreTexture(_name, OgreDataManager::getInstance().getGroup()); + mTextures[_name] = texture; + return texture; + } + + void destroyTexture(ITexture* _texture) + { + if (_texture == nullptr) return; + + MapTexture::iterator item = mTextures.find(_texture->getName()); + MYGUI_PLATFORM_ASSERT(item != mTextures.end(), "Texture '" << _texture->getName() << "' not found"); + + mTextures.erase(item); + delete _texture; + } + + ITexture* getTexture(const std::string& _name) + { + MapTexture::const_iterator item = mTextures.find(_name); + if (item == mTextures.end()) + { + Ogre::TexturePtr texture = (Ogre::TexturePtr)Ogre::TextureManager::getSingleton().getByName(_name); + if (!texture.isNull()) + { + ITexture* result = createTexture(_name); + static_cast(result)->setOgreTexture(texture); + return result; + } + return nullptr; + } + return item->second; + } + + bool isFormatSupported(PixelFormat _format, TextureUsage _usage) + { + return Ogre::TextureManager::getSingleton().isFormatSupported( + Ogre::TEX_TYPE_2D, + OgreTexture::convertFormat(_format), + OgreTexture::convertUsage(_usage)); + } + + void destroyAllResources() + { + for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) + { + delete item->second; + } + mTextures.clear(); + } + +#if MYGUI_DEBUG_MODE == 1 + bool checkTexture(ITexture* _texture) + { + for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) + { + if (item->second == _texture) + return true; + } + return false; + } +#endif + + const IntSize& getViewSize() const + { + return mViewSize; + } + + VertexColourType getVertexFormat() + { + return mVertexFormat; + } + + const RenderTargetInfo& getInfo() + { + return mInfo; + } + + size_t getActiveViewport() + { + return mActiveViewport; + } + + Ogre::RenderWindow* getRenderWindow() + { + return mWindow; + } + + bool getManualRender() + { + return mManualRender; + } + + void setManualRender(bool _value) + { + mManualRender = _value; + } + + size_t getBatchCount() const + { + return mCountBatch; + } +}; + +} + + void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir) { assert(wnd); @@ -41,8 +574,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new OgreRenderManager(); - mDataManager = new FixedOgreDataManager(); + mRenderManager = new MyGUI::ShaderBasedRenderManager(); + mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index 16673ef980..eec867ff8b 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,7 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; - class OgreRenderManager; + class ShaderBasedRenderManager; } namespace Ogre @@ -25,7 +25,7 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mRenderManager; Ogre::SceneManager* mSceneMgr; From d97b341dc6de0b640e55e14a5f467c5d75344b38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:02:21 -0700 Subject: [PATCH 0966/1483] Rename NIFMeshLoader to NIFObjectLoader --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d89d0d30a5..130e940208 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1012,11 +1012,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, std::map NIFMaterialLoader::MaterialMap; -/** Manual resource loader for NIF meshes. This is the main class - responsible for translating the internal NIF mesh structure into - something Ogre can use. +/** Manual resource loader for NIF objects (meshes, particle systems, etc). + * This is the main class responsible for translating the internal NIF + * structures into something Ogre can use. */ -class NIFMeshLoader : Ogre::ManualResourceLoader +class NIFObjectLoader : Ogre::ManualResourceLoader { std::string mName; std::string mGroup; @@ -1296,7 +1296,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } - typedef std::map LoaderMap; + typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -1399,7 +1399,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } - NIFMeshLoader(const std::string &name, const std::string &group) + NIFObjectLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1421,13 +1421,13 @@ class NIFMeshLoader : Ogre::ManualResourceLoader createSubMesh(mesh, dynamic_cast(record)); } - void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) + void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) { - // Do not create meshes for the collision shape (includes all children) + // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) return; - // Marker objects: just skip the entire node + // Marker objects: just skip the entire node branch /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) return; @@ -1483,7 +1483,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { - NIFMeshLoader *loader = &sLoaders[fullname]; + NIFObjectLoader *loader = &sLoaders[fullname]; *loader = *this; loader->mShapeIndex = shape->recIndex; @@ -1543,7 +1543,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createEntities(sceneMgr, children[i].getPtr(), entities, flags); + createObjects(sceneMgr, children[i].getPtr(), entities, flags); } } } @@ -1561,7 +1561,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { - NIFMeshLoader *loader = &sLoaders[fullname]; + NIFObjectLoader *loader = &sLoaders[fullname]; *loader = *this; mesh = meshMgr.createManual(fullname, mGroup, loader); @@ -1572,7 +1572,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } public: - NIFMeshLoader() : mShapeIndex(~(size_t)0) + NIFObjectLoader() : mShapeIndex(~(size_t)0) { } static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) @@ -1601,13 +1601,13 @@ public: if(!hasSkel) hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - NIFMeshLoader meshldr(name, group); + NIFObjectLoader meshldr(name, group); if(hasSkel) meshldr.createSkelBase(sceneMgr, node, entities); - meshldr.createEntities(sceneMgr, node, entities); + meshldr.createObjects(sceneMgr, node, entities); } }; -NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; +NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) @@ -1615,7 +1615,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, EntityList entitylist; Misc::StringUtils::toLower(name); - NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); for(size_t i = 0;i < entitylist.mEntities.size();i++) { @@ -1634,7 +1634,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); bool isskinned = false; for(size_t i = 0;i < entitylist.mEntities.size();i++) From 834a6a1f009c2741465a99605f0b1a06661b0c58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:14:26 -0700 Subject: [PATCH 0967/1483] Remove old, unused code --- components/nifogre/ogrenifloader.cpp | 44 +--------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 130e940208..99c6a65dcf 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1719,46 +1719,4 @@ Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group return NIFSkeletonLoader::createSkeleton(name, group, node); } - -/* 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 - in the file was given a separate bone in a skeleton. Unfortunately - the OGRE skeletons can't hold more than 256 bones, and some NIFs go - way beyond that. The code might be of use if we implement animated - submeshes like this (the part of the NIF that is animated is - usually much less than the entire file, but the method might still - not be water tight.) - -// Insert a raw RGBA image into the texture system. -extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height, void *data) -{ - TexturePtr texture = TextureManager::getSingleton().createManual( - name, // name - "General", // group - TEX_TYPE_2D, // type - width, height, // width & height - 0, // number of mipmaps - PF_BYTE_RGBA, // pixel format - TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - // Get the pixel buffer - HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - - // Lock the pixel buffer and get a pixel box - pixelBuffer->lock(HardwareBuffer::HBL_NORMAL); // for best performance use HBL_DISCARD! - const PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - void *dest = pixelBox.data; - - // Copy the data - memcpy(dest, data, width*height*4); - - // Unlock the pixel buffer - pixelBuffer->unlock(); -} - - -*/ - -} // nsmaepace NifOgre +} // namespace NifOgre From 2db72ae607926627e95032f7e7d8f177b7da2478 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:52:35 -0700 Subject: [PATCH 0968/1483] Rename EntityList to ObjectList --- apps/openmw/mwrender/activatoranimation.cpp | 6 +- apps/openmw/mwrender/animation.cpp | 44 ++++++------ apps/openmw/mwrender/animation.hpp | 4 +- apps/openmw/mwrender/creatureanimation.cpp | 6 +- apps/openmw/mwrender/npcanimation.cpp | 54 +++++++-------- apps/openmw/mwrender/npcanimation.hpp | 6 +- apps/openmw/mwrender/objects.cpp | 26 +++---- apps/openmw/mwrender/sky.cpp | 18 ++--- components/nifogre/ogrenifloader.cpp | 76 ++++++++++----------- components/nifogre/ogrenifloader.hpp | 18 ++--- 10 files changed, 129 insertions(+), 129 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 961c070038..b1b820915d 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -25,10 +25,10 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) { std::string mesh = "meshes\\" + ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(mPtr.getRefData().getBaseNode(), mesh); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *ent = mEntityList.mEntities[i]; + Ogre::Entity *ent = mObjectList.mEntities[i]; for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2b980320da..1d983acfc5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -40,21 +40,21 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mEntityList.mParticles.size();i++) - sceneMgr->destroyParticleSystem(mEntityList.mParticles[i]); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) - sceneMgr->destroyEntity(mEntityList.mEntities[i]); + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + sceneMgr->destroyParticleSystem(mObjectList.mParticles[i]); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) + sceneMgr->destroyEntity(mObjectList.mEntities[i]); } - mEntityList.mControllers.clear(); - mEntityList.mParticles.clear(); - mEntityList.mEntities.clear(); - mEntityList.mSkelBase = NULL; + mObjectList.mControllers.clear(); + mObjectList.mParticles.clear(); + mObjectList.mEntities.clear(); + mObjectList.mSkelBase = NULL; } void Animation::setAnimationSources(const std::vector &names) { - if(!mEntityList.mSkelBase) + if(!mObjectList.mSkelBase) return; mCurrentAnim = NULL; @@ -87,7 +87,7 @@ void Animation::setAnimationSources(const std::vector &names) if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); } mSkeletonSources.push_back(skel); @@ -105,15 +105,15 @@ void Animation::setAnimationSources(const std::vector &names) } } -void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) +void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) { mInsert = node->createChildSceneNode(); assert(mInsert); - mEntityList = NifOgre::Loader::createEntities(mInsert, model); - if(mEntityList.mSkelBase) + mObjectList = NifOgre::Loader::createObjects(mInsert, model); + if(mObjectList.mSkelBase) { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateSet *aset = mObjectList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -125,17 +125,17 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mEntityList.mControllers.size();i++) + for(size_t i = 0;i < mObjectList.mControllers.size();i++) { - if(mEntityList.mControllers[i].getSource().isNull()) - mEntityList.mControllers[i].setSource(ctrlval); + if(mObjectList.mControllers[i].getSource().isNull()) + mObjectList.mControllers[i].setSource(ctrlval); } } @@ -242,7 +242,7 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. - mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) @@ -289,7 +289,7 @@ Ogre::Vector3 Animation::updatePosition(float time) mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); else mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); - applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); + applyAnimation(mCurrentAnim, mCurrentTime, mObjectList.mSkelBase->getSkeleton()); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) @@ -465,8 +465,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mEntityList.mControllers.size();i++) - mEntityList.mControllers[i].update(); + for(size_t i = 0;i < mObjectList.mControllers.size();i++) + mObjectList.mControllers[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3e7dee6db2..55aaca427c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -40,7 +40,7 @@ protected: MWMechanics::CharacterController *mController; Ogre::SceneNode* mInsert; - NifOgre::EntityList mEntityList; + NifOgre::ObjectList mObjectList; std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; @@ -91,7 +91,7 @@ protected: setAnimationSources(names); } - void createEntityList(Ogre::SceneNode *node, const std::string &model); + void createObjectList(Ogre::SceneNode *node, const std::string &model); public: Animation(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 22f84ee018..a8c4afc4e8 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -25,10 +25,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), model); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(mPtr.getRefData().getBaseNode(), model); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *ent = mEntityList.mEntities[i]; + Ogre::Entity *ent = mObjectList.mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b7bcad5995..5d14440e75 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -50,7 +50,7 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - removeEntities(mEntityParts[i]); + removeObjects(mObjectParts[i]); } @@ -94,10 +94,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - createEntityList(node, smodel); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(node, smodel); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *base = mEntityList.mEntities[i]; + Ogre::Entity *base = mObjectList.mEntities[i]; base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if (mVisibilityFlags != 0) @@ -302,11 +302,11 @@ void NpcAnimation::updateParts(bool forceupdate) } } -NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename) +NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { - NifOgre::EntityList entities = NifOgre::Loader::createEntities(mEntityList.mSkelBase, bonename, - mInsert, mesh); - std::vector &parts = entities.mEntities; + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, + mInsert, model); + const std::vector &parts = objects.mEntities; for(size_t i = 0;i < parts.size();i++) { parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); @@ -319,9 +319,9 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - if(entities.mSkelBase) + if(objects.mSkelBase) { - Ogre::AnimationStateSet *aset = entities.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -329,12 +329,12 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int state->setEnabled(false); state->setLoop(false); } - Ogre::SkeletonInstance *skelinst = entities.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = objects.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } - return entities; + return objects; } Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) @@ -347,10 +347,10 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); + const Ogre::SkeletonInstance *skelsrc = mObjectList.mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { - Ogre::Entity *ent = mEntityParts[i].mSkelBase; + Ogre::Entity *ent = mObjectParts[i].mSkelBase; if(!ent) continue; updateSkeletonInstance(skelsrc, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); @@ -358,19 +358,19 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) return ret; } -void NpcAnimation::removeEntities(NifOgre::EntityList &entities) +void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) { - assert(&entities != &mEntityList); + assert(&objects != &mObjectList); Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < entities.mParticles.size();i++) - sceneMgr->destroyParticleSystem(entities.mParticles[i]); - for(size_t i = 0;i < entities.mEntities.size();i++) - sceneMgr->destroyEntity(entities.mEntities[i]); - entities.mControllers.clear(); - entities.mParticles.clear(); - entities.mEntities.clear(); - entities.mSkelBase = NULL; + for(size_t i = 0;i < objects.mParticles.size();i++) + sceneMgr->destroyParticleSystem(objects.mParticles[i]); + for(size_t i = 0;i < objects.mEntities.size();i++) + sceneMgr->destroyEntity(objects.mEntities[i]); + objects.mControllers.clear(); + objects.mParticles.clear(); + objects.mEntities.clear(); + objects.mSkelBase = NULL; } void NpcAnimation::removeIndividualPart(int type) @@ -382,7 +382,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeEntities(mEntityParts[i]); + removeObjects(mObjectParts[i]); break; } } @@ -420,7 +420,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - mEntityParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); + mObjectParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); break; } } @@ -451,7 +451,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorgetSkeleton()->getBone("Bip01 Head"); + return mObjectList.mSkelBase->getSkeleton()->getBone("Bip01 Head"); } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 5da4afef8a..41c29f7638 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -33,7 +33,7 @@ private: int mStateID; // Bounded Parts - NifOgre::EntityList mEntityParts[sPartListSize]; + NifOgre::ObjectList mObjectParts[sPartListSize]; const ESM::NPC *mNpc; std::string mHeadModel; @@ -60,11 +60,11 @@ private: int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[sPartListSize]; - NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); + NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename); void updateParts(bool forceupdate = false); - void removeEntities(NifOgre::EntityList &entities); + void removeObjects(NifOgre::ObjectList &objects); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 8c5d4cad3a..3456e1c16a 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -130,9 +130,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::EntityList entities = NifOgre::Loader::createEntities(insert, mesh); - for(size_t i = 0;i < entities.mEntities.size();i++) - bounds.merge(entities.mEntities[i]->getWorldBoundingBox(true)); + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(insert, mesh); + for(size_t i = 0;i < objects.mEntities.size();i++) + bounds.merge(objects.mEntities[i]->getWorldBoundingBox(true)); Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); @@ -149,9 +149,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool mBounds[ptr.getCell()].merge(bounds); bool anyTransparency = false; - for(size_t i = 0;!anyTransparency && i < entities.mEntities.size();i++) + for(size_t i = 0;!anyTransparency && i < objects.mEntities.size();i++) { - Ogre::Entity *ent = entities.mEntities[i]; + Ogre::Entity *ent = objects.mEntities[i]; for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i) { anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent(); @@ -159,11 +159,11 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool } if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || - anyTransparency || entities.mParticles.size() > 0) + anyTransparency || objects.mParticles.size() > 0) { - for(size_t i = 0;i < entities.mEntities.size();i++) + for(size_t i = 0;i < objects.mEntities.size();i++) { - Ogre::Entity *ent = entities.mEntities[i]; + Ogre::Entity *ent = objects.mEntities[i]; for(unsigned int i=0; i < ent->getNumSubEntities(); ++i) { Ogre::SubEntity* subEnt = ent->getSubEntity(i); @@ -172,9 +172,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } - for(size_t i = 0;i < entities.mParticles.size();i++) + for(size_t i = 0;i < objects.mParticles.size();i++) { - Ogre::ParticleSystem *part = entities.mParticles[i]; + Ogre::ParticleSystem *part = objects.mParticles[i]; // TODO: Check the particle system's material for actual transparency part->setRenderQueueGroup(RQG_Alpha); part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); @@ -225,8 +225,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool sg->setRenderQueueGroup(RQG_Main); - std::vector::reverse_iterator iter = entities.mEntities.rbegin(); - while(iter != entities.mEntities.rend()) + std::vector::reverse_iterator iter = objects.mEntities.rbegin(); + while(iter != objects.mEntities.rend()) { Ogre::Node *node = (*iter)->getParentNode(); sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); @@ -239,7 +239,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool if (light) { - insertLight(ptr, entities.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); + insertLight(ptr, objects.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); } } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 94af3521b3..7f3abce701 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -288,10 +288,10 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::Loader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); - for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); + for(size_t i = 0, matidx = 0;i < objects.mEntities.size();i++) { - Entity* night1_ent = entities.mEntities[i]; + Entity* night1_ent = objects.mEntities[i]; night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); @@ -314,10 +314,10 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::Loader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); - for(size_t i = 0;i < entities.mEntities.size();i++) + objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); + for(size_t i = 0;i < objects.mEntities.size();i++) { - Entity* atmosphere_ent = entities.mEntities[i]; + Entity* atmosphere_ent = objects.mEntities[i]; atmosphere_ent->setCastShadows(false); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); @@ -332,10 +332,10 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::Loader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); - for(size_t i = 0;i < entities.mEntities.size();i++) + objects = NifOgre::Loader::createObjects(clouds_node, "meshes\\sky_clouds_01.nif"); + for(size_t i = 0;i < objects.mEntities.size();i++) { - Entity* clouds_ent = entities.mEntities[i]; + Entity* clouds_ent = objects.mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 99c6a65dcf..e7d1a88d1c 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1421,7 +1421,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader createSubMesh(mesh, dynamic_cast(record)); } - void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) + void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags=0) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -1460,12 +1460,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::SharedPtr > srcval; /* Filled in later */ Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); - entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } @@ -1494,16 +1494,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::Entity *entity = sceneMgr->createEntity(mesh); entity->setVisible(!(flags&0x01)); - entities.mEntities.push_back(entity); - if(entities.mSkelBase) + objectlist.mEntities.push_back(entity); + if(objectlist.mSkelBase) { if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(entities.mSkelBase); + entity->shareSkeletonInstanceWith(objectlist.mSkelBase); else { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); - entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } } @@ -1519,7 +1519,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); - entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } @@ -1528,11 +1528,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) { - Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); + Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) { partsys->setVisible(!(flags&0x01)); - entities.mParticles.push_back(partsys); + objectlist.mParticles.push_back(partsys); } } @@ -1543,12 +1543,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(sceneMgr, children[i].getPtr(), entities, flags); + createObjects(sceneMgr, children[i].getPtr(), objectlist, flags); } } } - void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities) + void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all @@ -1567,15 +1567,15 @@ class NIFObjectLoader : Ogre::ManualResourceLoader mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - entities.mSkelBase = sceneMgr->createEntity(mesh); - entities.mEntities.push_back(entities.mSkelBase); + objectlist.mSkelBase = sceneMgr->createEntity(mesh); + objectlist.mEntities.push_back(objectlist.mSkelBase); } public: NIFObjectLoader() : mShapeIndex(~(size_t)0) { } - static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) + static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) { Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); @@ -1603,44 +1603,44 @@ public: NIFObjectLoader meshldr(name, group); if(hasSkel) - meshldr.createSkelBase(sceneMgr, node, entities); - meshldr.createObjects(sceneMgr, node, entities); + meshldr.createSkelBase(sceneMgr, node, objectlist); + meshldr.createObjects(sceneMgr, node, objectlist); } }; NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; -EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) +ObjectList Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { - EntityList entitylist; + ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group); - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(!entity->isAttached()) parentNode->attachObject(entity); } - return entitylist; + return objectlist; } -EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, const std::string &group) +ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, const std::string &group) { - EntityList entitylist; + ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group); bool isskinned = false; - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *ent = entitylist.mEntities[i]; - if(entitylist.mSkelBase != ent && ent->hasSkeleton()) + Ogre::Entity *ent = objectlist.mEntities[i]; + if(objectlist.mSkelBase != ent && ent->hasSkeleton()) { isskinned = true; break; @@ -1655,12 +1655,12 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen { std::string filter = "@shape=tri "+bonename; Misc::StringUtils::toLower(filter); - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(entity->hasSkeleton()) { - if(entity == entitylist.mSkelBase || + if(entity == objectlist.mSkelBase || entity->getMesh()->getName().find(filter) != std::string::npos) parentNode->attachObject(entity); } @@ -1673,9 +1673,9 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } else { - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(!entity->isAttached()) { Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); @@ -1684,7 +1684,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } } - return entitylist; + return objectlist; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 819b4d8806..ee50aa86e5 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -39,7 +39,7 @@ namespace NifOgre typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; -struct EntityList { +struct ObjectList { Ogre::Entity *mSkelBase; std::vector mEntities; @@ -47,7 +47,7 @@ struct EntityList { std::vector > mControllers; - EntityList() : mSkelBase(0) + ObjectList() : mSkelBase(0) { } }; @@ -55,14 +55,14 @@ struct EntityList { class Loader { public: - static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); + static ObjectList createObjects(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, + const std::string &group="General"); - static EntityList createEntities(Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); + static ObjectList createObjects(Ogre::SceneNode *parentNode, + std::string name, + const std::string &group="General"); static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); }; From 878b4c15c5631fa3daa75a80d1fd44cb7e917a36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 02:08:33 -0700 Subject: [PATCH 0969/1483] Set visibility flags and the render queue group for particles --- apps/openmw/mwrender/activatoranimation.cpp | 9 ++++++- apps/openmw/mwrender/creatureanimation.cpp | 8 ++++++ apps/openmw/mwrender/npcanimation.cpp | 30 ++++++++++++++++----- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index b1b820915d..4630208b4b 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -1,6 +1,7 @@ #include "activatoranimation.hpp" #include +#include #include #include @@ -29,14 +30,20 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) for(size_t i = 0;i < mObjectList.mEntities.size();i++) { Ogre::Entity *ent = mObjectList.mEntities[i]; + ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { Ogre::SubEntity* subEnt = ent->getSubEntity(j); subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } + } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + part->setVisibilityFlags(RV_Misc); - ent->setVisibilityFlags(RV_Misc); + part->setRenderQueueGroup(RQG_Alpha); } setAnimationSource(mesh); } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index a8c4afc4e8..c714a2372a 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,6 +1,7 @@ #include "creatureanimation.hpp" #include +#include #include #include @@ -37,6 +38,13 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + part->setVisibilityFlags(RV_Actors); + + part->setRenderQueueGroup(RQG_Alpha); + } std::vector names; if((ref->mBase->mFlags&ESM::Creature::Biped)) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5d14440e75..28c78fd2f7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -109,6 +110,15 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + + part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); + if(mVisibilityFlags != 0) + part->setVisibilityFlags(mVisibilityFlags); + part->setRenderQueueGroup(RQG_Alpha); + } std::vector skelnames(1, smodel); if(!mNpc->isMale() && !isBeast) @@ -306,19 +316,25 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in { NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, mInsert, model); - const std::vector &parts = objects.mEntities; - for(size_t i = 0;i < parts.size();i++) + for(size_t i = 0;i < objects.mEntities.size();i++) { - parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if (mVisibilityFlags != 0) - parts[i]->setVisibilityFlags(mVisibilityFlags); + objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + if(mVisibilityFlags != 0) + objects.mEntities[i]->setVisibilityFlags(mVisibilityFlags); - for(unsigned int j=0; j < parts[i]->getNumSubEntities(); ++j) + for(unsigned int j=0; j < objects.mEntities[i]->getNumSubEntities(); ++j) { - Ogre::SubEntity* subEnt = parts[i]->getSubEntity(j); + Ogre::SubEntity* subEnt = objects.mEntities[i]->getSubEntity(j); subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < objects.mParticles.size();i++) + { + objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + if(mVisibilityFlags != 0) + objects.mParticles[i]->setVisibilityFlags(mVisibilityFlags); + objects.mParticles[i]->setRenderQueueGroup(RQG_Alpha); + } if(objects.mSkelBase) { Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); From be419bc89185c74be619d08054e94e8aad0cec71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 02:28:15 -0700 Subject: [PATCH 0970/1483] Handle NiCamera nodes --- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 1 + components/nifogre/ogrenifloader.cpp | 8 ++++++++ components/nifogre/ogrenifloader.hpp | 7 ++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1d983acfc5..23d2d9e1b6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,6 +46,7 @@ Animation::~Animation() sceneMgr->destroyEntity(mObjectList.mEntities[i]); } mObjectList.mControllers.clear(); + mObjectList.mCameras.clear(); mObjectList.mParticles.clear(); mObjectList.mEntities.clear(); mObjectList.mSkelBase = NULL; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 28c78fd2f7..931b8ef83d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -384,6 +384,7 @@ void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) for(size_t i = 0;i < objects.mEntities.size();i++) sceneMgr->destroyEntity(objects.mEntities[i]); objects.mControllers.clear(); + objects.mCameras.clear(); objects.mParticles.clear(); objects.mEntities.clear(); objects.mSkelBase = NULL; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e7d1a88d1c..7dd616e4ee 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -498,6 +498,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles )) @@ -1452,6 +1453,13 @@ class NIFObjectLoader : Ogre::ManualResourceLoader e = e->extra; } + if(node->recType == Nif::RC_NiCamera) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, node->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mCameras.push_back(trgtbone); + } + Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index ee50aa86e5..88cbaf6910 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -42,9 +42,14 @@ static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct ObjectList { Ogre::Entity *mSkelBase; std::vector mEntities; - std::vector mParticles; + // We could actually have Ogre::Camera objects, but that means more + // maintenance when switching cameras. The information in the NiCamera node + // is pretty much useless too anyway. So instead, this is just a list of + // bones in the mSkelBase which are NiCamera nodes. + std::vector mCameras; + std::vector > mControllers; ObjectList() : mSkelBase(0) From ff1d908af416d8301dda9f1f82d8947c1213d4f4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 15:17:35 +0200 Subject: [PATCH 0971/1483] added script table --- apps/esmtool/record.cpp | 2 +- apps/opencs/model/world/data.cpp | 15 +++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadscpt.cpp | 15 +++++++++++++-- components/esm/loadscpt.hpp | 5 ++++- 10 files changed, 56 insertions(+), 5 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a6f77862ef..e16ade6e24 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1182,7 +1182,7 @@ void Record::print() std::cout << " Variable: " << *vit << std::endl; std::cout << " ByteCode: "; - std::vector::iterator cit; + std::vector::iterator cit; for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); cit++) std::cout << boost::format("%02X") % (int)(*cit); std::cout << std::endl; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 69109bd743..c29cdaccfb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -84,6 +84,9 @@ CSMWorld::Data::Data() mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); mSounds.addColumn (new SoundFileColumn); + mScripts.addColumn (new StringIdColumn); + mScripts.addColumn (new RecordStateColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -91,6 +94,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); + addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); } CSMWorld::Data::~Data() @@ -169,6 +173,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSounds() return mSounds; } +const CSMWorld::IdCollection& CSMWorld::Data::getScripts() const +{ + return mScripts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getScripts() +{ + return mScripts; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -210,6 +224,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_FACT: mFactions.load (reader, base); break; case ESM::REC_RACE: mRaces.load (reader, base); break; case ESM::REC_SOUN: mSounds.load (reader, base); break; + case ESM::REC_SCPT: mScripts.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 320480e639..7daf5d4baa 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -30,6 +31,7 @@ namespace CSMWorld IdCollection mFactions; IdCollection mRaces; IdCollection mSounds; + IdCollection mScripts; std::vector mModels; std::map mModelIndex; @@ -74,6 +76,10 @@ namespace CSMWorld IdCollection& getSounds(); + const IdCollection& getScripts() const; + + IdCollection& getScripts(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 7bdc15c8c7..816681a133 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -24,6 +24,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -37,6 +38,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index a21d67fcd8..06db75d7f4 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -47,7 +47,9 @@ namespace CSMWorld Type_Races, Type_Race, Type_Sounds, - Type_Sound + Type_Sound, + Type_Scripts, + Type_Script }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 611690ca65..27cf78b3ce 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -109,6 +109,10 @@ void CSVDoc::View::setupWorldMenu() QAction *sounds = new QAction (tr ("Sounds"), this); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); world->addAction (sounds); + + QAction *scripts = new QAction (tr ("Scripts"), this); + connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView())); + world->addAction (scripts); } void CSVDoc::View::setupUi() @@ -289,6 +293,11 @@ void CSVDoc::View::addSoundsSubView() addSubView (CSMWorld::UniversalId::Type_Sounds); } +void CSVDoc::View::addScriptsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Scripts); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index e8e716b706..4822db3e4f 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -125,6 +125,8 @@ namespace CSVDoc void addRacesSubView(); void addSoundsSubView(); + + void addScriptsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 3ba950f879..7cdf18bce6 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -21,6 +21,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Factions, CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_Sounds, + CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index d9b6497d98..2c1b018d97 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -64,7 +64,7 @@ void Script::save(ESMWriter &esm) memcpy(data.mName.name, mId.c_str(), mId.size()); esm.writeHNT("SCHD", data, 52); - + if (!mVarNames.empty()) { esm.startSubRecord("SCVR"); @@ -76,10 +76,21 @@ void Script::save(ESMWriter &esm) } esm.startSubRecord("SCDT"); - esm.write(&mScriptData[0], mData.mScriptDataSize); + esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); esm.endRecord("SCDT"); esm.writeHNOString("SCTX", mScriptText); } + void Script::blank() + { + mData.mNumShorts = mData.mNumLongs = mData.mNumFloats = 0; + mData.mScriptDataSize = 0; + mData.mStringTableSize = 0; + + mVarNames.clear(); + mScriptData.clear(); + mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n"; + } + } diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 10a6d24b10..be7e839002 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -52,11 +52,14 @@ public: SCHDstruct mData; std::vector mVarNames; // Variable names - std::vector mScriptData; // Compiled bytecode + std::vector mScriptData; // Compiled bytecode std::string mScriptText; // Uncompiled script void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 755a80a522963f6d6b26f39134bd6696c917756c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 15:52:43 +0200 Subject: [PATCH 0972/1483] Fix camera shaking when near the pitch limit. --- apps/openmw/mwrender/player.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 63396378d0..55fda326fa 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -242,14 +242,15 @@ namespace MWRender void Player::setPitch(float angle) { - float limit = Ogre::Math::HALF_PI; + const float epsilon = 0.000001; + float limit = Ogre::Math::HALF_PI - epsilon; if (mVanity.forced || mPreviewMode) { limit /= 2; } if (angle > limit) { - angle = limit - 0.01; + angle = limit; } else if (angle < -limit) { - angle = -limit + 0.01; + angle = -limit; } if (mVanity.enabled || mPreviewMode) { mPreviewCam.pitch = angle; From ebff64a7a4b297c2b9a34a808c19d4b57ee8dee9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 06:56:12 -0700 Subject: [PATCH 0973/1483] Fix UVController and add warn about unhandled material controllers --- components/nifogre/ogrenifloader.cpp | 63 ++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 7dd616e4ee..8924056e03 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -184,18 +184,23 @@ public: static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) { - Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); + if(keys.mKeys.size() == 0) + return def; + + if(time <= keys.mKeys.front().mTime) + return keys.mKeys.front().mValue; + + Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()+1); for(;iter != keys.mKeys.end();iter++) { - if(iter->mTime > time) + if(iter->mTime < time) continue; - Nif::FloatKeyList::VecType::const_iterator next(iter+1); - if(next == keys.mKeys.end()) - return iter->mValue; - float a = (time-iter->mTime) / (next->mTime-iter->mTime); - return iter->mValue + ((next->mValue - iter->mValue)*a); + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); } - return def; + return keys.mKeys.back().mValue; } public: @@ -837,6 +842,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, else warn("Found internal texture, ignoring."); } + + Nif::ControllerPtr ctrls = texprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled texture controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); @@ -845,6 +857,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, { alphaFlags = alphaprop->flags; alphaTest = alphaprop->data.threshold; + + Nif::ControllerPtr ctrls = alphaprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled alpha controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } // Vertex color handling @@ -853,17 +872,38 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, vertMode = vertprop->data.vertmode; // FIXME: Handle lightmode? //lightMode = vertprop->data.lightmode; + + Nif::ControllerPtr ctrls = vertprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } if(zprop) { depthFlags = zprop->flags; // Depth function??? + + Nif::ControllerPtr ctrls = zprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled depth controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } if(specprop) { specFlags = specprop->flags; + + Nif::ControllerPtr ctrls = specprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled specular controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } // Material @@ -875,6 +915,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, emissive = matprop->data.emissive; glossiness = matprop->data.glossiness; alpha = matprop->data.alpha; + + Nif::ControllerPtr ctrls = matprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled material controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } { From 2e067e95a9a63bbb25d12ecbe6fb969a4e638317 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:12:52 -0700 Subject: [PATCH 0974/1483] Handle NiWireframeProperty --- components/nifogre/ogrenifloader.cpp | 37 +++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8924056e03..94cb14b588 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -799,6 +799,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, const Nif::NiVertexColorProperty *vertprop, const Nif::NiZBufferProperty *zprop, const Nif::NiSpecularProperty *specprop, + const Nif::NiWireframeProperty *wireprop, bool &needTangents) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); @@ -819,6 +820,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, int depthFlags = 3; // Default should be 1, but Bloodmoon's models are broken int specFlags = 0; + int wireFlags = 0; Ogre::String texName[7]; bool vertexColour = (shapedata->colors.size() != 0); @@ -906,6 +908,18 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, } } + if(wireprop) + { + wireFlags = wireprop->flags; + + Nif::ControllerPtr ctrls = wireprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + // Material if(matprop) { @@ -950,6 +964,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, boost::hash_combine(h, vertMode); boost::hash_combine(h, depthFlags); boost::hash_combine(h, specFlags); + boost::hash_combine(h, wireFlags); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -993,6 +1008,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } + if(wireFlags) + { + instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); + } + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); @@ -1087,10 +1107,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiAlphaProperty *&alphaprop, const Nif::NiVertexColorProperty *&vertprop, const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop) + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *wireprop) { if(node->parent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); const Nif::PropertyList &proplist = node->props; for(size_t i = 0;i < proplist.length();i++) @@ -1112,6 +1133,8 @@ class NIFObjectLoader : Ogre::ManualResourceLoader zprop = static_cast(pr); else if(pr->recType == Nif::RC_NiSpecularProperty) specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } @@ -1324,13 +1347,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, - needTangents); + wireprop, needTangents); if(matname.length() > 0) sub->setMaterialName(matname); @@ -1405,13 +1429,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, - needTangents)); + wireprop, needTangents)); partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); partsys->setCullIndividually(false); From 8bbfba3f43afa56d62c63b310700384d50fcfaa4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 16:18:40 +0200 Subject: [PATCH 0975/1483] Fix fatigue not being set to its maximum value when player is rebuilt --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8757213e99..4a2a2ecc69 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -149,7 +149,7 @@ namespace MWMechanics // forced update and current value adjustments mActors.updateActor (ptr, 0); - for (int i=0; i<2; ++i) + for (int i=0; i<3; ++i) { DynamicStat stat = creatureStats.getDynamic (i); stat.setCurrent (stat.getModified()); From e25f5c6dfe71b5c076ccd01dce5048f575ac5aa5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 16:32:06 +0200 Subject: [PATCH 0976/1483] added basic region table --- apps/opencs/model/world/data.cpp | 16 ++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadregn.cpp | 19 ++++++++++++++++--- components/esm/loadregn.hpp | 3 +++ 9 files changed, 58 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c29cdaccfb..0c6f2b4ada 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -87,6 +87,10 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); + mRegions.addColumn (new StringIdColumn); + mRegions.addColumn (new RecordStateColumn); + mRegions.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -95,6 +99,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); + addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); } CSMWorld::Data::~Data() @@ -183,6 +188,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getScripts() return mScripts; } +const CSMWorld::IdCollection& CSMWorld::Data::getRegions() const +{ + return mRegions; +} + +CSMWorld::IdCollection& CSMWorld::Data::getRegions() +{ + return mRegions; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -225,6 +240,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_RACE: mRaces.load (reader, base); break; case ESM::REC_SOUN: mSounds.load (reader, base); break; case ESM::REC_SCPT: mScripts.load (reader, base); break; + case ESM::REC_REGN: mRegions.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 7daf5d4baa..d9432aa3e3 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -32,6 +33,7 @@ namespace CSMWorld IdCollection mRaces; IdCollection mSounds; IdCollection mScripts; + IdCollection mRegions; std::vector mModels; std::map mModelIndex; @@ -80,6 +82,10 @@ namespace CSMWorld IdCollection& getScripts(); + const IdCollection& getRegions() const; + + IdCollection& getRegions(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 816681a133..4a81ee01b5 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -25,6 +25,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -39,6 +40,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 06db75d7f4..507febba44 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -49,7 +49,9 @@ namespace CSMWorld Type_Sounds, Type_Sound, Type_Scripts, - Type_Script + Type_Script, + Type_Regions, + Type_Region }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 27cf78b3ce..8e51ba9dcb 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -113,6 +113,10 @@ void CSVDoc::View::setupWorldMenu() QAction *scripts = new QAction (tr ("Scripts"), this); connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView())); world->addAction (scripts); + + QAction *regions = new QAction (tr ("Regions"), this); + connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); + world->addAction (regions); } void CSVDoc::View::setupUi() @@ -298,6 +302,11 @@ void CSVDoc::View::addScriptsSubView() addSubView (CSMWorld::UniversalId::Type_Scripts); } +void CSVDoc::View::addRegionsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Regions); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 4822db3e4f..a5190dedc6 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -127,6 +127,8 @@ namespace CSVDoc void addSoundsSubView(); void addScriptsSubView(); + + void addRegionsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 7cdf18bce6..30812f8f58 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -22,6 +22,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_Scripts, + CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index d39a294547..41c7f507ae 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -31,14 +31,14 @@ void Region::load(ESMReader &esm) void Region::save(ESMWriter &esm) { esm.writeHNCString("FNAM", mName); - + if (esm.getVersion() == VER_12) esm.writeHNT("WEAT", mData, sizeof(mData) - 2); else esm.writeHNT("WEAT", mData); - + esm.writeHNOCString("BNAM", mSleepList); - + esm.writeHNT("CNAM", mMapColor); for (std::vector::iterator it = mSoundList.begin(); it != mSoundList.end(); ++it) { @@ -46,4 +46,17 @@ void Region::save(ESMWriter &esm) } } + void Region::blank() + { + mName.clear(); + + mData.mClear = mData.mCloudy = mData.mFoggy = mData.mOvercast = mData.mRain = + mData.mThunder = mData.mAsh, mData.mBlight = mData.mA = mData.mB = 0; + + mMapColor = 0; + + mName.clear(); + mSleepList.clear(); + mSoundList.clear(); + } } diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 0496ef5af2..f2a3d9a108 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -48,6 +48,9 @@ struct Region void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 88c81bfb243164d185723dfbe8e266bf58611034 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:38:43 -0700 Subject: [PATCH 0977/1483] Apply polygon_mode to objects --- files/materials/objects.mat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 49df4e3949..957d75db56 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -17,6 +17,7 @@ material openmw_objects_base depth_check default alpha_rejection default transparent_sorting default + polygon_mode default pass { @@ -41,6 +42,7 @@ material openmw_objects_base depth_write $depth_write depth_check $depth_check transparent_sorting $transparent_sorting + polygon_mode $polygon_mode texture_unit diffuseMap { From fe9a7f12b6c21bc6dc4ebc8ac22fb5fc767a0b81 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:53:01 -0700 Subject: [PATCH 0978/1483] Material fixes --- components/nifogre/ogrenifloader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 94cb14b588..3bd8b95e58 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -947,9 +947,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, boost::hash_combine(h, diffuse.x); boost::hash_combine(h, diffuse.y); boost::hash_combine(h, diffuse.z); + boost::hash_combine(h, alpha); boost::hash_combine(h, specular.x); boost::hash_combine(h, specular.y); boost::hash_combine(h, specular.z); + boost::hash_combine(h, glossiness); boost::hash_combine(h, emissive.x); boost::hash_combine(h, emissive.y); boost::hash_combine(h, emissive.z); @@ -1108,7 +1110,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *&vertprop, const Nif::NiZBufferProperty *&zprop, const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *wireprop) + const Nif::NiWireframeProperty *&wireprop) { if(node->parent) getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); From f49a2a97c5f09a30703448b28cadbe17adf963ce Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 16:56:21 +0200 Subject: [PATCH 0979/1483] added map colour column to region table --- apps/opencs/model/world/columns.hpp | 34 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 35 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 75dfe15c27..b09c931b28 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -5,6 +5,8 @@ #include +#include + #include "columnbase.hpp" namespace CSMWorld @@ -591,6 +593,38 @@ namespace CSMWorld return true; } }; + + /// \todo QColor is a GUI class and should not be in model. Need to think of an alternative + /// solution. + template + struct MapColourColumn : public Column + { + /// \todo Replace Display_Integer with something that displays the colour value more directly. + MapColourColumn() : Column ("Map Colour", ColumnBase::Display_Integer) {} + + virtual QVariant get (const Record& record) const + { + int colour = record.get().mMapColor; + + return QColor (colour & 0xff, (colour>>8) & 0xff, (colour>>16) & 0xff); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + QColor colour = data.value(); + + record2.mMapColor = colour.rgb() & 0xffffff; + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0c6f2b4ada..f451656875 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -90,6 +90,7 @@ CSMWorld::Data::Data() mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); mRegions.addColumn (new NameColumn); + mRegions.addColumn (new MapColourColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From ab5980ae187b8e8e71167353368c0598a83bc26f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 08:29:56 -0700 Subject: [PATCH 0980/1483] Let the default controller function use absolute input And convert the VisController to use it. --- components/nifogre/ogrenifloader.cpp | 84 ++++++++++++++-------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3bd8b95e58..e5e072620e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -75,24 +75,33 @@ private: float mStopTime; public: - DefaultFunction(const Nif::Controller *ctrl) - : Ogre::ControllerFunction(false) + DefaultFunction(const Nif::Controller *ctrl, bool deltaInput) + : Ogre::ControllerFunction(deltaInput) , mFrequency(ctrl->frequency) , mPhase(ctrl->phase) , mStartTime(ctrl->timeStart) , mStopTime(ctrl->timeStop) { - mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); + if(mDeltaInput) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } } virtual Ogre::Real calculate(Ogre::Real value) { - mDeltaCount += value*mFrequency; - mDeltaCount = std::fmod(mDeltaCount - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; + if(mDeltaInput) + { + mDeltaCount += value*mFrequency; + mDeltaCount = std::fmod(mDeltaCount - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + + value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); + return value; } }; @@ -103,6 +112,20 @@ public: { private: Ogre::Bone *mTarget; + std::vector mData; + + virtual bool calculate(Ogre::Real time) + { + if(mData.size() == 0) + return true; + + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > time) + return mData[i-1].isSet; + } + return mData.back().isSet; + } // FIXME: We are not getting all objects here. Skinned meshes get // attached to the object's root node, and won't be connected via a @@ -126,7 +149,9 @@ public: } public: - Value(Ogre::Bone *target) : mTarget(target) + Value(Ogre::Bone *target, const Nif::NiVisData *data) + : mTarget(target) + , mData(data->mVis) { } virtual Ogre::Real getValue() const @@ -135,39 +160,14 @@ public: return 1.0f; } - virtual void setValue(Ogre::Real value) + virtual void setValue(Ogre::Real time) { - int vis = static_cast(value); + bool vis = calculate(time); setVisible(mTarget, vis); } }; - class Function : public Ogre::ControllerFunction - { - private: - std::vector mData; - - public: - Function(const Nif::NiVisData *data) - : Ogre::ControllerFunction(false), - mData(data->mVis) - { } - - virtual Ogre::Real calculate(Ogre::Real value) - { - if(mData.size() == 0) - return 1.0f; - - if(mData[0].time >= value) - return mData[0].isSet; - for(size_t i = 1;i < mData.size();i++) - { - if(mData[i].time > value) - return mData[i-1].isSet; - } - return mData.back().isSet; - } - }; + typedef DefaultFunction Function; }; class UVController @@ -1543,9 +1543,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::SharedPtr > srcval; /* Filled in later */ - Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); - Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, false)); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -1599,7 +1599,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, true)); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } From 399394ff103ec1f2779cdb8244caccff6da5621e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 10:03:13 -0700 Subject: [PATCH 0981/1483] Don't restrict animations to the keyframe time limits --- components/nifogre/ogrenifloader.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e5e072620e..90139c9f02 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -384,10 +384,8 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const lasttrans = curtrans = traniter->mValue; if(scaleiter != scalekeys.mKeys.end()) lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - float begTime = std::max(kfc->timeStart, startTime); - float endTime = std::min(kfc->timeStop, stopTime); - bool didlast = false; + bool didlast = false; while(!didlast) { float curtime = std::numeric_limits::max(); @@ -400,11 +398,11 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const if(scaleiter != scalekeys.mKeys.end()) curtime = std::min(curtime, scaleiter->mTime); - curtime = std::max(curtime, begTime); - if(curtime >= endTime) + curtime = std::max(curtime, startTime); + if(curtime >= stopTime) { didlast = true; - curtime = endTime; + curtime = stopTime; } // Get the latest quaternions, translations, and scales for the From 822866b5ae325a8a6a1bf29d1c09f4c8860f9104 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 7 Apr 2013 18:04:30 +0100 Subject: [PATCH 0982/1483] fixed autorun --- apps/openmw/mwinput/inputmanagerimp.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 74d581b811..0ed49cd7f7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -301,6 +301,12 @@ namespace MWInput mPlayer.setForwardBackward (-1); } + else if(mPlayer.getAutoMove()) + { + triedToMove = true; + mPlayer.setForwardBackward (1); + } + mPlayer.setSneak(actionIsActive(A_Sneak)); if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) @@ -321,6 +327,7 @@ namespace MWInput mOverencumberedMessageDelay -= dt; if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) { + mPlayer.setAutoMove (false); if (mOverencumberedMessageDelay <= 0) { MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); From c9424f577f15a35a6f1fe22d6681db39a48269fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 19:29:15 +0200 Subject: [PATCH 0983/1483] added sleeplist column to region table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b09c931b28..aa097dac65 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -625,6 +625,31 @@ namespace CSMWorld return true; } }; + + template + struct SleepListColumn : public Column + { + SleepListColumn() : Column ("Sleep Encounter", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mSleepList.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mSleepList = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f451656875..fc93675e42 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -91,6 +91,7 @@ CSMWorld::Data::Data() mRegions.addColumn (new RecordStateColumn); mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); + mRegions.addColumn (new SleepListColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 593646436ea4fe3dcabdb01b40c2fd5d45b0a279 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 19:39:13 +0200 Subject: [PATCH 0984/1483] added verifier for region record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/regioncheck.cpp | 33 +++++++++++++++++++++++++ apps/opencs/model/tools/regioncheck.hpp | 29 ++++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/regioncheck.cpp create mode 100644 apps/opencs/model/tools/regioncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ffd4c7f1ea..301febfc49 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck ) diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp new file mode 100644 index 0000000000..ac64ac0271 --- /dev/null +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -0,0 +1,33 @@ + +#include "regioncheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::RegionCheckStage::RegionCheckStage (const CSMWorld::IdCollection& regions) +: mRegions (regions) +{} + +int CSMTools::RegionCheckStage::setup() +{ + return mRegions.getSize(); +} + +void CSMTools::RegionCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Region& region = mRegions.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Region, region.mId); + + // test for empty name + if (region.mName.empty()) + messages.push_back (id.toString() + "|" + region.mId + " has an empty name"); + + /// \todo test that the ID in mSleeplist exists + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/regioncheck.hpp b/apps/opencs/model/tools/regioncheck.hpp new file mode 100644 index 0000000000..b421356514 --- /dev/null +++ b/apps/opencs/model/tools/regioncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_REGIONCHECK_H +#define CSM_TOOLS_REGIONCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that region records are internally consistent + class RegionCheckStage : public Stage + { + const CSMWorld::IdCollection& mRegions; + + public: + + RegionCheckStage (const CSMWorld::IdCollection& regions); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 4003bc8840..45adcf5e49 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -17,6 +17,7 @@ #include "factioncheck.hpp" #include "racecheck.hpp" #include "soundcheck.hpp" +#include "regioncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -66,6 +67,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); + + mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); } return mVerifier; From 80a1abd48ad5bc37e604c820249d8d7d250cd91c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 11:09:55 -0700 Subject: [PATCH 0985/1483] Clear the old text keys when setting new animation sources --- apps/openmw/mwrender/animation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 23d2d9e1b6..8ecebc7070 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -63,6 +63,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimVelocity = 0.0f; mAccumRoot = NULL; mNonAccumRoot = NULL; + mTextKeys.clear(); mSkeletonSources.clear(); std::vector::const_iterator nameiter; @@ -96,7 +97,7 @@ void Animation::setAnimationSources(const std::vector &names) { Ogre::Animation *anim = skel->getAnimation(i); const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); + "@"+anim->getName()); if(!groupdata.isEmpty()) mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); } From 60cc95305d101c820856684186b7fb3beabf1e8f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 20:26:39 +0200 Subject: [PATCH 0986/1483] added basic birthsign table --- apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadbsgn.cpp | 8 ++++++++ components/esm/loadbsgn.hpp | 3 +++ 9 files changed, 51 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fc93675e42..70162ba758 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -93,6 +93,11 @@ CSMWorld::Data::Data() mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); + mBirthsigns.addColumn (new StringIdColumn); + mBirthsigns.addColumn (new RecordStateColumn); + mBirthsigns.addColumn (new NameColumn); + mBirthsigns.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -102,6 +107,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); + addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); } CSMWorld::Data::~Data() @@ -200,6 +206,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getRegions() return mRegions; } +const CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() const +{ + return mBirthsigns; +} + +CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() +{ + return mBirthsigns; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -243,6 +259,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SOUN: mSounds.load (reader, base); break; case ESM::REC_SCPT: mScripts.load (reader, base); break; case ESM::REC_REGN: mRegions.load (reader, base); break; + case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index d9432aa3e3..122e855d86 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -34,6 +35,7 @@ namespace CSMWorld IdCollection mSounds; IdCollection mScripts; IdCollection mRegions; + IdCollection mBirthsigns; std::vector mModels; std::map mModelIndex; @@ -86,6 +88,10 @@ namespace CSMWorld IdCollection& getRegions(); + const IdCollection& getBirthsigns() const; + + IdCollection& getBirthsigns(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 4a81ee01b5..6d305d6c0f 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -26,6 +26,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -41,6 +42,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 507febba44..0586719f14 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -51,7 +51,9 @@ namespace CSMWorld Type_Scripts, Type_Script, Type_Regions, - Type_Region + Type_Region, + Type_Birthsigns, + Type_Birthsign }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 8e51ba9dcb..af9b814203 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -117,6 +117,10 @@ void CSVDoc::View::setupWorldMenu() QAction *regions = new QAction (tr ("Regions"), this); connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); world->addAction (regions); + + QAction *birthsigns = new QAction (tr ("Birthsigns"), this); + connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView())); + world->addAction (birthsigns); } void CSVDoc::View::setupUi() @@ -307,6 +311,11 @@ void CSVDoc::View::addRegionsSubView() addSubView (CSMWorld::UniversalId::Type_Regions); } +void CSVDoc::View::addBirthsignsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Birthsigns); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index a5190dedc6..12944e5693 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -129,6 +129,8 @@ namespace CSVDoc void addScriptsSubView(); void addRegionsSubView(); + + void addBirthsignsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 30812f8f58..23c66319c6 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -23,6 +23,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_Regions, + CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index b58071644c..cb500f6748 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -24,4 +24,12 @@ void BirthSign::save(ESMWriter &esm) mPowers.save(esm); } + void BirthSign::blank() + { + mName.clear(); + mDescription.clear(); + mTexture.clear(); + mPowers.mList.clear(); + } + } diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index b0bc28be48..434ddf68ea 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -20,6 +20,9 @@ struct BirthSign void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From baf8eaecb82f75168eaac998c9795faa18c3b72e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 20:46:04 +0200 Subject: [PATCH 0987/1483] added texture column to birthsign table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index aa097dac65..fbc533779a 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -650,6 +650,31 @@ namespace CSMWorld return true; } }; + + template + struct TextureColumn : public Column + { + TextureColumn() : Column ("Texture", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mTexture.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mTexture = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 70162ba758..b385c5b4c2 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -96,6 +96,7 @@ CSMWorld::Data::Data() mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); mBirthsigns.addColumn (new NameColumn); + mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); From 2d2196b0d60d4b874af143e370547e72d14ef3ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:01:02 +0200 Subject: [PATCH 0988/1483] Implemented levelled items --- apps/openmw/mwworld/containerstore.cpp | 73 ++++++++++++++++++++++---- apps/openmw/mwworld/containerstore.hpp | 1 + components/esm/loadlevlist.hpp | 15 +++--- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index a377f2bbbf..8a5662986e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -14,6 +14,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" @@ -180,21 +182,72 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { - ManualRef ref (store, iter->mItem.toString()); - - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) - { - /// \todo implement leveled item lists - continue; - } - - ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) - addImp (ref.getPtr()); + std::string id = iter->mItem.toString(); + addInitialItem(id, iter->mCount); } flagAsModified(); } +void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, unsigned char failChance, bool topLevel) +{ + count = std::abs(count); /// \todo implement item restocking (indicated by negative count) + + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); + + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + { + const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; + const std::vector& items = levItem->mList; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); + + failChance += levItem->mChanceNone; + + if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) + { + for (int i=0; i (std::rand()) / RAND_MAX; + if (random >= failChance/100.f) + { + std::vector candidates; + int highestLevel = 0; + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (it->mLevel > highestLevel) + highestLevel = it->mLevel; + } + + std::pair highest = std::make_pair(-1, ""); + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (playerLevel >= it->mLevel + && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + { + candidates.push_back(it->mId); + if (it->mLevel >= highest.first) + highest = std::make_pair(it->mLevel, it->mId); + } + + } + if (!candidates.size()) + return; + std::string item = candidates[std::rand()%candidates.size()]; + addInitialItem(item, count, failChance, false); + } + } + else + { + ref.getPtr().getRefData().setCount (count); + addImp (ref.getPtr()); + } +} + void MWWorld::ContainerStore::clear() { for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 9d315d27f0..a466c3c2a9 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -53,6 +53,7 @@ namespace MWWorld mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr); + void addInitialItem (const std::string& id, int count, unsigned char failChance=0, bool topLevel=true); public: diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index b7db5db360..aa9656d724 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -22,17 +22,20 @@ struct LeveledListBase { enum Flags { - AllLevels = 0x01, // Calculate from all levels <= player - // level, not just the closest below - // player. - Each = 0x02 // Select a new item each time this + + Each = 0x01, // Select a new item each time this // list is instantiated, instead of // giving several identical items - }; // (used when a container has more + // (used when a container has more // than one instance of one leveled // list.) + AllLevels = 0x02 // Calculate from all levels <= player + // level, not just the closest below + // player. + }; + int mFlags; - unsigned char mChanceNone; // Chance that none are selected (0-255?) + unsigned char mChanceNone; // Chance that none are selected (0-100) std::string mId; // Record name used to read references. Must be set before load() is From f3c8cd2065ee3f781d3259464e7b1b2943f1f842 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:38:53 +0200 Subject: [PATCH 0989/1483] Don't buy/sell keys which are set to open a lock --- apps/openmw/mwclass/apparatus.cpp | 5 +++++ apps/openmw/mwclass/apparatus.hpp | 2 ++ apps/openmw/mwclass/armor.cpp | 5 +++++ apps/openmw/mwclass/armor.hpp | 2 ++ apps/openmw/mwclass/book.cpp | 5 +++++ apps/openmw/mwclass/book.hpp | 2 ++ apps/openmw/mwclass/clothing.cpp | 5 +++++ apps/openmw/mwclass/clothing.hpp | 2 ++ apps/openmw/mwclass/ingredient.cpp | 5 +++++ apps/openmw/mwclass/ingredient.hpp | 2 ++ apps/openmw/mwclass/light.cpp | 5 +++++ apps/openmw/mwclass/light.hpp | 2 ++ apps/openmw/mwclass/lockpick.cpp | 5 +++++ apps/openmw/mwclass/lockpick.hpp | 2 ++ apps/openmw/mwclass/misc.cpp | 8 ++++++++ apps/openmw/mwclass/misc.hpp | 2 ++ apps/openmw/mwclass/potion.cpp | 5 +++++ apps/openmw/mwclass/potion.hpp | 2 ++ apps/openmw/mwclass/probe.cpp | 5 +++++ apps/openmw/mwclass/probe.hpp | 2 ++ apps/openmw/mwclass/repair.cpp | 5 +++++ apps/openmw/mwclass/repair.hpp | 2 ++ apps/openmw/mwclass/weapon.cpp | 5 +++++ apps/openmw/mwclass/weapon.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 27 +-------------------------- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ components/esm/loadnpc.hpp | 2 +- 28 files changed, 97 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 851a5ae360..32c1277318 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -159,4 +159,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mAppas.insert(*ref), &cell); } + + bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Apparatus; + } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 7045f62d6f..d4917c6186 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -54,6 +54,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 320944d3ce..e62985d3dc 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -315,4 +315,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Armor; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 65f49abb7d..16905d65cc 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -74,6 +74,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 85b006160b..b658295f85 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -183,4 +183,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Books; + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 29e3de0361..3f083f5525 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -59,6 +59,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index abad267675..98480f06f2 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -262,4 +262,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Clothing; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index c3ef22f113..2e5bb424fb 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -68,6 +68,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 14cf6ff6f9..0afe60e0e2 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -197,4 +197,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mIngreds.insert(*ref), &cell); } + + bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Ingredients; + } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 0afd202fb4..d27a7cbb0e 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -56,6 +56,8 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7466657725..306c6bbb6a 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -203,4 +203,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mLights.insert(*ref), &cell); } + + bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Lights; + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 640e1705bd..7d919f75df 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 2015726968..bfbf107565 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -176,4 +176,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mLockpicks.insert(*ref), &cell); } + + bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Picks; + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 0961b55b24..edd884a3e0 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8cfac1a686..02307cc021 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -246,4 +246,12 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionSoulgem(ptr)); } + bool Miscellaneous::canSell (const MWWorld::Ptr& item, int npcServices) const + { + MWWorld::LiveCellRef *ref = + item.get(); + + return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc); + } + } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 12a50af19d..ba00900bd0 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -53,6 +53,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 37461ed905..ad2826ea83 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -194,4 +194,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mPotions.insert(*ref), &cell); } + + bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Potions; + } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index d595f7e694..845795d0e8 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -52,6 +52,8 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index e4533af655..4ec6a8340b 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -175,4 +175,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mProbes.insert(*ref), &cell); } + + bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Probes; + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index d9f90baf6d..75ebaa01cb 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index bafedee88b..36e7068252 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -175,4 +175,9 @@ namespace MWClass { return boost::shared_ptr(new MWWorld::ActionRepair(ptr)); } + + bool Repair::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::RepairItem; + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 3083c97e35..a545cf4d60 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -61,6 +61,8 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exceoption) + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0a527262f8..3df1ced7df 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -409,4 +409,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Weapon::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Weapon; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 4774bb50be..084ceeca2b 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -73,6 +73,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 81a29e69bd..73904371ed 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -356,32 +356,7 @@ namespace MWGui services = ref->mBase->mAiData.mServices; } - /// \todo what about potions, there doesn't seem to be a flag for them?? - - if (item.getTypeName() == typeid(ESM::Weapon).name()) - return services & ESM::NPC::Weapon; - else if (item.getTypeName() == typeid(ESM::Armor).name()) - return services & ESM::NPC::Armor; - else if (item.getTypeName() == typeid(ESM::Clothing).name()) - return services & ESM::NPC::Clothing; - else if (item.getTypeName() == typeid(ESM::Book).name()) - return services & ESM::NPC::Books; - else if (item.getTypeName() == typeid(ESM::Ingredient).name()) - return services & ESM::NPC::Ingredients; - else if (item.getTypeName() == typeid(ESM::Lockpick).name()) - return services & ESM::NPC::Picks; - else if (item.getTypeName() == typeid(ESM::Probe).name()) - return services & ESM::NPC::Probes; - else if (item.getTypeName() == typeid(ESM::Light).name()) - return services & ESM::NPC::Lights; - else if (item.getTypeName() == typeid(ESM::Apparatus).name()) - return services & ESM::NPC::Apparatus; - else if (item.getTypeName() == typeid(ESM::Repair).name()) - return services & ESM::NPC::RepairItem; - else if (item.getTypeName() == typeid(ESM::Miscellaneous).name()) - return services & ESM::NPC::Misc; - - return false; + return MWWorld::Class::get(item).canSell(item, services); } std::vector TradeWindow::itemsToIgnore() diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2dfa241b3b..0f8d40e931 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -47,6 +47,11 @@ namespace MWWorld throw std::runtime_error ("class does not represent an actor"); } + bool Class::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return false; + } + MWMechanics::CreatureStats& Class::getCreatureStats (const Ptr& ptr) const { throw std::runtime_error ("class does not have creature stats"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index de4741e38b..49e0ff0032 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -238,6 +238,9 @@ namespace MWWorld virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const; + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices + virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 46be29961d..b30077f23c 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -35,11 +35,11 @@ struct NPC Apparatus = 0x00100, RepairItem = 0x00200, Misc = 0x00400, + Potions = 0x02000, // Other services Spells = 0x00800, MagicItems = 0x01000, - Potions = 0x02000, Training = 0x04000, // What skills? Spellmaking = 0x08000, Enchanting = 0x10000, From 2362e920f309b272994cd1763f7e668fc7033de8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 12:41:27 -0700 Subject: [PATCH 0990/1483] Use an unconnected object list for animation sources We'll want the controllers, as the plan is to use their keyframe controllers to animate the actual skeleton used for the meshes. --- apps/openmw/mwrender/animation.cpp | 52 ++++++++++++++++++---------- apps/openmw/mwrender/animation.hpp | 3 +- components/nifogre/ogrenifloader.cpp | 29 +++------------- components/nifogre/ogrenifloader.hpp | 4 ++- 4 files changed, 42 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8ecebc7070..686fbbb848 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,6 +16,19 @@ namespace MWRender { +void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) +{ + for(size_t i = 0;i < objects.mParticles.size();i++) + sceneMgr->destroyParticleSystem(objects.mParticles[i]); + for(size_t i = 0;i < objects.mEntities.size();i++) + sceneMgr->destroyEntity(objects.mEntities[i]); + objects.mControllers.clear(); + objects.mCameras.clear(); + objects.mParticles.clear(); + objects.mEntities.clear(); + objects.mSkelBase = NULL; +} + Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mController(NULL) @@ -40,16 +53,12 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mObjectList.mParticles.size();i++) - sceneMgr->destroyParticleSystem(mObjectList.mParticles[i]); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) - sceneMgr->destroyEntity(mObjectList.mEntities[i]); + destroyObjectList(sceneMgr, mObjectList); + + for(size_t i = 0;i < mAnimationSources.size();i++) + destroyObjectList(sceneMgr, mAnimationSources[i]); + mAnimationSources.clear(); } - mObjectList.mControllers.clear(); - mObjectList.mCameras.clear(); - mObjectList.mParticles.clear(); - mObjectList.mEntities.clear(); - mObjectList.mSkelBase = NULL; } @@ -57,6 +66,7 @@ void Animation::setAnimationSources(const std::vector &names) { if(!mObjectList.mSkelBase) return; + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); mCurrentAnim = NULL; mCurrentKeys = NULL; @@ -64,19 +74,24 @@ void Animation::setAnimationSources(const std::vector &names) mAccumRoot = NULL; mNonAccumRoot = NULL; mTextKeys.clear(); - mSkeletonSources.clear(); + for(size_t i = 0;i < mAnimationSources.size();i++) + destroyObjectList(sceneMgr, mAnimationSources[i]); + mAnimationSources.clear(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { - Ogre::SkeletonPtr skel = NifOgre::Loader::getSkeleton(*nameiter); - if(skel.isNull()) + mAnimationSources.push_back(NifOgre::Loader::createObjectBase(sceneMgr, *nameiter)); + if(!mAnimationSources.back().mSkelBase) { std::cerr<< "Failed to get skeleton source "<<*nameiter <touch(); + Ogre::Entity *ent = mAnimationSources.back().mSkelBase; + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { @@ -92,7 +107,6 @@ void Animation::setAnimationSources(const std::vector &names) mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); } - mSkeletonSources.push_back(skel); for(int i = 0;i < skel->getNumAnimations();i++) { Ogre::Animation *anim = skel->getAnimation(i); @@ -144,9 +158,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mSkeletonSources.begin());iter != mSkeletonSources.end();iter++) + for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) { - if((*iter)->hasAnimation(anim)) + if(iter->mSkelBase->hasAnimationState(anim)) return true; } return false; @@ -413,11 +427,11 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::const_reverse_iterator iter(mSkeletonSources.rbegin());iter != mSkeletonSources.rend();iter++) + for(std::vector::const_reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) { - if((*iter)->hasAnimation(groupname)) + if(iter->mSkelBase->hasAnimationState(groupname)) { - mCurrentAnim = (*iter)->getAnimation(groupname); + mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; mAnimVelocity = 0.0f; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 55aaca427c..22ab9fc7eb 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -47,7 +47,7 @@ protected: Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::vector mSkeletonSources; + std::vector mAnimationSources; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -92,6 +92,7 @@ protected: } void createObjectList(Ogre::SceneNode *node, const std::string &model); + static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); public: Animation(const MWWorld::Ptr &ptr); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 90139c9f02..d3da77e41e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1768,35 +1768,14 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena } -Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group) +ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string name, const std::string &group) { - Ogre::SkeletonPtr skel; + ObjectList objectlist; Misc::StringUtils::toLower(name); - skel = Ogre::SkeletonManager::getSingleton().getByName(name); - if(!skel.isNull()) - return skel; + NIFObjectLoader::load(sceneMgr, objectlist, name, group); - Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); - if(nif->numRoots() < 1) - { - nif->warn("Found no root nodes in "+name+"."); - return skel; - } - - // The first record is assumed to be the root node - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); - - const Nif::Node *node = dynamic_cast(r); - if(node == NULL) - { - nif->warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return skel; - } - - return NIFSkeletonLoader::createSkeleton(name, group, node); + return objectlist; } } // namespace NifOgre diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 88cbaf6910..3a7a22f8b1 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -69,7 +69,9 @@ public: std::string name, const std::string &group="General"); - static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); + static ObjectList createObjectBase(Ogre::SceneManager *sceneMgr, + std::string name, + const std::string &group="General"); }; } From 480467b6ebf693004cbc3df2232ff981465a086f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:53:11 +0200 Subject: [PATCH 0991/1483] Reset the 'owner' field for items that were legitimately bought from an NPC. --- apps/openmw/mwgui/tradewindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 73904371ed..7756484fa5 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -257,6 +257,12 @@ namespace MWGui MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); // success! make the item transfer. + MWWorld::ContainerStore& playerBoughtItems = mWindowManager.getInventoryWindow()->getBoughtItems(); + for (MWWorld::ContainerStoreIterator it = playerBoughtItems.begin(); it != playerBoughtItems.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->getCellRef().mOwner, MWWorld::Class::get(mPtr).getId(mPtr))) + it->getCellRef().mOwner = ""; + } transferBoughtItems(); mWindowManager.getInventoryWindow()->transferBoughtItems(); From 7494f90301bcf35a6d3560b495b4f61455b05c9c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 13:02:46 -0700 Subject: [PATCH 0992/1483] Remove an unneeded function --- apps/openmw/mwrender/npcanimation.cpp | 21 +++------------------ apps/openmw/mwrender/npcanimation.hpp | 1 - 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 931b8ef83d..253dbb0ff7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -50,8 +50,9 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize NpcAnimation::~NpcAnimation() { + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); for(size_t i = 0;i < sPartListSize;i++) - removeObjects(mObjectParts[i]); + destroyObjectList(sceneMgr, mObjectParts[i]); } @@ -374,22 +375,6 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) return ret; } -void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) -{ - assert(&objects != &mObjectList); - - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < objects.mParticles.size();i++) - sceneMgr->destroyParticleSystem(objects.mParticles[i]); - for(size_t i = 0;i < objects.mEntities.size();i++) - sceneMgr->destroyEntity(objects.mEntities[i]); - objects.mControllers.clear(); - objects.mCameras.clear(); - objects.mParticles.clear(); - objects.mEntities.clear(); - objects.mSkelBase = NULL; -} - void NpcAnimation::removeIndividualPart(int type) { mPartPriorities[type] = 0; @@ -399,7 +384,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeObjects(mObjectParts[i]); + destroyObjectList(mInsert->getCreator(), mObjectParts[i]); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 41c29f7638..b59051a8d6 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -64,7 +64,6 @@ private: void updateParts(bool forceupdate = false); - void removeObjects(NifOgre::ObjectList &objects); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); From 44a59e1b87805627390d44d8ba02710476445d7a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 13:03:41 -0700 Subject: [PATCH 0993/1483] Fix a couple messages --- components/nifogre/ogrenifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d3da77e41e..d02c0816e3 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1092,12 +1092,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader static void warn(const std::string &msg) { - std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl; } static void fail(const std::string &msg) { - std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + std::cerr << "NIFObjectLoader: Fail: "<< msg << std::endl; abort(); } From 9e08497f0200b8ea42ad3e6116b868ebca7adbf6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 22:07:04 +0200 Subject: [PATCH 0994/1483] Initial container content should inherit the owner of its container --- apps/openmw/mwworld/cells.cpp | 6 +++--- apps/openmw/mwworld/containerstore.cpp | 11 ++++++----- apps/openmw/mwworld/containerstore.hpp | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 5f771be475..4838cfefa5 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -45,7 +45,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, container.getCellRef().mOwner, mStore); } for (CellRefList::List::iterator iter ( @@ -55,7 +55,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, Class::get(container).getId(container), mStore); } for (CellRefList::List::iterator iter ( @@ -65,7 +65,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, Class::get(container).getId(container), mStore); } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8a5662986e..05026a98ba 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -177,19 +177,19 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr return it; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWorld::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const MWWorld::ESMStore& store) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = iter->mItem.toString(); - addInitialItem(id, iter->mCount); + addInitialItem(id, owner, iter->mCount); } flagAsModified(); } -void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, unsigned char failChance, bool topLevel) +void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, unsigned char failChance, bool topLevel) { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) @@ -208,7 +208,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i Date: Sun, 7 Apr 2013 13:46:29 -0700 Subject: [PATCH 0995/1483] Update animation source controller targets --- apps/openmw/mwrender/animation.cpp | 14 ++++++++++++++ components/nifogre/ogrenifloader.cpp | 9 ++++----- components/nifogre/ogrenifloader.hpp | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 686fbbb848..f3ecbd6a51 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,6 +78,7 @@ void Animation::setAnimationSources(const std::vector &names) destroyObjectList(sceneMgr, mAnimationSources[i]); mAnimationSources.clear(); + Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { @@ -89,6 +90,19 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.pop_back(); continue; } + const NifOgre::ObjectList &objects = mAnimationSources.back(); + + for(size_t i = 0;i < objects.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval = dynamic_cast*>(objects.mControllers[i].getDestination().getPointer()); + if(!dstval) continue; + + const Ogre::String &trgtname = dstval->getNode()->getName(); + if(!skelinst->hasBone(trgtname)) continue; + + Ogre::Bone *bone = skelinst->getBone(trgtname); + dstval->setNode(bone); + } Ogre::Entity *ent = mAnimationSources.back().mSkelBase; Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d02c0816e3..a0aefaccc9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -108,10 +108,9 @@ public: class VisController { public: - class Value : public Ogre::ControllerValue + class Value : public NodeTargetValue { private: - Ogre::Bone *mTarget; std::vector mData; virtual bool calculate(Ogre::Real time) @@ -149,8 +148,8 @@ public: } public: - Value(Ogre::Bone *target, const Nif::NiVisData *data) - : mTarget(target) + Value(Ogre::Node *target, const Nif::NiVisData *data) + : NodeTargetValue(target) , mData(data->mVis) { } @@ -163,7 +162,7 @@ public: virtual void setValue(Ogre::Real time) { bool vis = calculate(time); - setVisible(mTarget, vis); + setVisible(mNode, vis); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 3a7a22f8b1..18bbf0200f 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -74,6 +74,24 @@ public: const std::string &group="General"); }; +// FIXME: Should be with other general Ogre extensions. +template +class NodeTargetValue : public Ogre::ControllerValue +{ +protected: + Ogre::Node *mNode; + +public: + NodeTargetValue(Ogre::Node *target) : mNode(target) + { } + + void setNode(Ogre::Node *target) + { mNode = target; } + Ogre::Node *getNode() const + { return mNode; } +}; +typedef Ogre::SharedPtr > NodeTargetValueRealPtr; + } namespace std From 43a501369080f633f829a4b3e64e87b960d738ec Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 23:25:35 +0200 Subject: [PATCH 0996/1483] added verifier for birthsign record --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/tools/birthsigncheck.cpp | 39 ++++++++++++++++++++++ apps/opencs/model/tools/birthsigncheck.hpp | 29 ++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 72 insertions(+) create mode 100644 apps/opencs/model/tools/birthsigncheck.cpp create mode 100644 apps/opencs/model/tools/birthsigncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 301febfc49..87221d7af5 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -36,6 +36,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck + birthsigncheck ) diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp new file mode 100644 index 0000000000..b673c93ded --- /dev/null +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -0,0 +1,39 @@ + +#include "birthsigncheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns) +: mBirthsigns (birthsigns) +{} + +int CSMTools::BirthsignCheckStage::setup() +{ + return mBirthsigns.getSize(); +} + +void CSMTools::BirthsignCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::BirthSign& birthsign = mBirthsigns.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId); + + // test for empty name, description and texture + if (birthsign.mName.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty name"); + + if (birthsign.mDescription.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty description"); + + if (birthsign.mTexture.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " is missing a texture"); + + /// \todo test if the texture exists + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/birthsigncheck.hpp b/apps/opencs/model/tools/birthsigncheck.hpp new file mode 100644 index 0000000000..42b5a6b244 --- /dev/null +++ b/apps/opencs/model/tools/birthsigncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_BIRTHSIGNCHECK_H +#define CSM_TOOLS_BIRTHSIGNCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that birthsign records are internally consistent + class BirthsignCheckStage : public Stage + { + const CSMWorld::IdCollection& mBirthsigns; + + public: + + BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 45adcf5e49..78796de418 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -18,6 +18,7 @@ #include "racecheck.hpp" #include "soundcheck.hpp" #include "regioncheck.hpp" +#include "birthsigncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -69,6 +70,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); + + mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); } return mVerifier; From 261ea1fe5e137386e4b859bcbae6b519d4fa3b1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 14:56:23 -0700 Subject: [PATCH 0997/1483] Implement a KeyframeController --- apps/openmw/mwrender/animation.cpp | 21 ++++-- apps/openmw/mwrender/animation.hpp | 1 + components/nifogre/ogrenifloader.cpp | 107 +++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f3ecbd6a51..fd7aeac1d0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -37,6 +37,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) , mLastPosition(0.0f) + , mCurrentControllers(NULL) , mCurrentKeys(NULL) , mCurrentAnim(NULL) , mCurrentTime(0.0f) @@ -68,6 +69,7 @@ void Animation::setAnimationSources(const std::vector &names) return; Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + mCurrentControllers = &mObjectList.mControllers; mCurrentAnim = NULL; mCurrentKeys = NULL; mAnimVelocity = 0.0f; @@ -78,6 +80,7 @@ void Animation::setAnimationSources(const std::vector &names) destroyObjectList(sceneMgr, mAnimationSources[i]); mAnimationSources.clear(); + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) @@ -90,7 +93,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.pop_back(); continue; } - const NifOgre::ObjectList &objects = mAnimationSources.back(); + NifOgre::ObjectList &objects = mAnimationSources.back(); for(size_t i = 0;i < objects.mControllers.size();i++) { @@ -104,7 +107,13 @@ void Animation::setAnimationSources(const std::vector &names) dstval->setNode(bone); } - Ogre::Entity *ent = mAnimationSources.back().mSkelBase; + for(size_t i = 0;i < objects.mControllers.size();i++) + { + if(objects.mControllers[i].getSource().isNull()) + objects.mControllers[i].setSource(ctrlval); + } + + Ogre::Entity *ent = objects.mSkelBase; Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -167,6 +176,7 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model if(mObjectList.mControllers[i].getSource().isNull()) mObjectList.mControllers[i].setSource(ctrlval); } + mCurrentControllers = &mObjectList.mControllers; } @@ -441,12 +451,13 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::const_reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) + for(std::vector::reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) { if(iter->mSkelBase->hasAnimationState(groupname)) { mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; if(mNonAccumRoot) @@ -495,8 +506,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mObjectList.mControllers.size();i++) - mObjectList.mControllers[i].update(); + for(size_t i = 0;i < mCurrentControllers->size();i++) + (*mCurrentControllers)[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 22ab9fc7eb..aee139bd67 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -49,6 +49,7 @@ protected: std::vector mAnimationSources; + std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a0aefaccc9..e7bf820b8e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -169,6 +169,101 @@ public: typedef DefaultFunction Function; }; +class KeyframeController +{ +public: + class Value : public NodeTargetValue + { + private: + Nif::QuaternionKeyList mRotations; + Nif::Vector3KeyList mTranslations; + Nif::FloatKeyList mScales; + + public: + Value(Ogre::Node *target, const Nif::NiKeyframeData *data) + : NodeTargetValue(target) + , mRotations(data->mRotations) + , mTranslations(data->mTranslations) + , mScales(data->mScales) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 0.0f; + } + + virtual void setValue(Ogre::Real time) + { + if(mRotations.mKeys.size() > 0) + { + if(time <= mRotations.mKeys.front().mTime) + mNode->setOrientation(mRotations.mKeys.front().mValue); + else if(time >= mRotations.mKeys.back().mTime) + mNode->setOrientation(mRotations.mKeys.back().mValue); + else + { + Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); + for(;iter != mRotations.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); + break; + } + } + } + if(mTranslations.mKeys.size() > 0) + { + if(time <= mTranslations.mKeys.front().mTime) + mNode->setPosition(mTranslations.mKeys.front().mValue); + else if(time >= mTranslations.mKeys.back().mTime) + mNode->setPosition(mTranslations.mKeys.back().mValue); + else + { + Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); + for(;iter != mTranslations.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::Vector3KeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); + break; + } + } + } + if(mScales.mKeys.size() > 0) + { + if(time <= mScales.mKeys.front().mTime) + mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); + else if(time >= mScales.mKeys.back().mTime) + mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); + else + { + Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); + for(;iter != mScales.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); + break; + } + } + } + } + }; + + typedef DefaultFunction Function; +}; + class UVController { public: @@ -1546,6 +1641,18 @@ class NIFObjectLoader : Ogre::ManualResourceLoader objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } + else if(ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } ctrl = ctrl->next; } From 3c633e275e99852ea48e8b8e1e49f3145c63e640 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 15:42:07 -0700 Subject: [PATCH 0998/1483] Don't create a controller for empty keyframe data --- components/nifogre/ogrenifloader.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e7bf820b8e..e06a23b5b9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1644,14 +1644,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader else if(ctrl->recType == Nif::RC_NiKeyframeController) { const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } } ctrl = ctrl->next; } From 7baca30a1d10bd0cef7b49e59be39e7df92692e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 16:21:45 -0700 Subject: [PATCH 0999/1483] Only get the non-accum root's keyframe when updating positions The actual animation pose is now handled by the controllers, based on the current animation time. --- apps/openmw/mwrender/animation.cpp | 80 ++++++++++++++---------------- apps/openmw/mwrender/animation.hpp | 9 ++-- 2 files changed, 40 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fd7aeac1d0..72f7ebaf2e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -263,28 +263,6 @@ void Animation::calcAnimVelocity() } } -void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) -{ - Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); - Ogre::Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator(); - while(tracks.hasMoreElements()) - { - Ogre::NodeAnimationTrack *track = tracks.getNext(); - const Ogre::String &targetname = track->getAssociatedNode()->getName(); - if(!skel->hasBone(targetname)) - continue; - Ogre::Bone *bone = skel->getBone(targetname); - bone->setOrientation(Ogre::Quaternion::IDENTITY); - bone->setPosition(Ogre::Vector3::ZERO); - bone->setScale(Ogre::Vector3::UNIT_SCALE); - track->applyToNode(bone, timeindex); - } - - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); -} - static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) { if(skelsrc->hasBone(bone->getName())) @@ -323,24 +301,29 @@ void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Og } -Ogre::Vector3 Animation::updatePosition(float time) +Ogre::Vector3 Animation::updatePosition() { - if(mLooping) - mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); - else - mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); - applyAnimation(mCurrentAnim, mCurrentTime, mObjectList.mSkelBase->getSkeleton()); + Ogre::Vector3 posdiff; - Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; - if(mNonAccumRoot) + Ogre::TransformKeyFrame kf(0, mCurrentTime); + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(trackiter.hasMoreElements()) { - /* Get the non-accumulation root's difference from the last update. */ - posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; - - /* Translate the accumulation root back to compensate for the move. */ - mLastPosition += posdiff; - mAccumRoot->setPosition(-mLastPosition); + const Ogre::NodeAnimationTrack *track = trackiter.getNext(); + if(track->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + { + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); + break; + } } + + /* Get the non-accumulation root's difference from the last update. */ + posdiff = (kf.getTranslate() - mLastPosition) * mAccumulate; + + /* Translate the accumulation root back to compensate for the move. */ + mLastPosition += posdiff; + mAccumRoot->setPosition(-mLastPosition); + return posdiff; } @@ -486,11 +469,14 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) timepassed *= mAnimSpeedMult; while(mCurrentAnim && mPlaying) { - float targetTime = std::min(mStopTime, mCurrentTime+timepassed); + float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - movement += updatePosition(targetTime); - mPlaying = (mLooping || mStopTime > targetTime); + mCurrentTime = std::min(mStopTime, targetTime); + if(mNonAccumRoot) + movement += updatePosition(); + mPlaying = (mLooping || mStopTime > mCurrentTime); + timepassed = targetTime - mCurrentTime; break; } @@ -498,10 +484,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) const std::string &evt = mNextKey->second; mNextKey++; - movement += updatePosition(time); - mPlaying = (mLooping || mStopTime > time); - - timepassed = targetTime - time; + mCurrentTime = time; + if(mNonAccumRoot) + movement += updatePosition(); + mPlaying = (mLooping || mStopTime > mCurrentTime); + timepassed = targetTime - mCurrentTime; if(!handleEvent(time, evt)) break; @@ -509,6 +496,13 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) for(size_t i = 0;i < mCurrentControllers->size();i++) (*mCurrentControllers)[i].update(); + if(mObjectList.mSkelBase) + { + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + } + return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index aee139bd67..2fcc1e8f70 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -63,16 +63,13 @@ protected: void calcAnimVelocity(); - /* Applies the given animation to the given skeleton instance, using the specified time. */ - void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); - /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); - /* Updates the animation to the specified time, and returns the movement - * vector since the last update or reset. */ - Ogre::Vector3 updatePosition(float time); + /* Updates the position of the accum root node for the current time, and + * returns the wanted movement vector from the previous update. */ + Ogre::Vector3 updatePosition(); /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If From dba7308248ef270a5a138c2f0470b9412e13e414 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 17:16:49 -0700 Subject: [PATCH 1000/1483] Recognize NiParticleRotation --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e06a23b5b9..ac1e8e056e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1487,13 +1487,17 @@ class NIFObjectLoader : Ogre::ManualResourceLoader affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } + else if(e->recType == Nif::RC_NiParticleRotation) + { + // TODO: Implement (Ogre::RotationAffector?) + } else if(e->recType == Nif::RC_NiParticleColorModifier) { // TODO: Implement (Ogre::ColourInterpolatorAffector?) } else if(e->recType == Nif::RC_NiGravity) { - // TODO: Implement (Ogre::LinearForceAffector?) + // TODO: Implement } else warn("Unhandled particle modifier "+e->recName); From c6c67a1bb49d22d93f6c9f6bf5859ddc4c5629f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 18:15:23 -0700 Subject: [PATCH 1001/1483] Read NiGravity fields --- components/nif/controlled.hpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 08c47defee..6acb8ff201 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -98,12 +98,23 @@ public: class NiGravity : public Controlled { public: + float mForce; + /* 0 - Wind (fixed direction) + * 1 - Point (fixed origin) + */ + int mType; + Ogre::Vector3 mPosition; + Ogre::Vector3 mDirection; + void read(NIFStream *nif) { Controlled::read(nif); - // two floats, one int, six floats - nif->skip(9*4); + /*unknown*/nif->getFloat(); + mForce = nif->getFloat(); + mType = nif->getUInt(); + mPosition = nif->getVector3(); + mDirection = nif->getVector3(); } }; From 08d43fe21787501b5a572c946268e8e2874b2410 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 05:48:52 -0700 Subject: [PATCH 1002/1483] Make the getHeadNode method more general --- apps/openmw/mwrender/animation.cpp | 12 ++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 5 ----- apps/openmw/mwrender/npcanimation.hpp | 2 -- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 72f7ebaf2e..067e856720 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -180,6 +180,18 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model } +Ogre::Node *Animation::getNode(const std::string &name) +{ + if(mObjectList.mSkelBase) + { + Ogre::SkeletonInstance *skel = mObjectList.mSkelBase->getSkeleton(); + if(skel->hasBone(name)) + return skel->getBone(name); + } + return NULL; +} + + bool Animation::hasAnimation(const std::string &anim) { for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2fcc1e8f70..cfef28f16c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -113,6 +113,8 @@ public: void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); + + Ogre::Node *getNode(const std::string &name); }; } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 843bcf007b..616543a7d4 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -201,7 +201,7 @@ namespace MWRender void RaceSelectionPreview::updateCamera() { Ogre::Vector3 scale = mNode->getScale(); - Ogre::Vector3 headOffset = mAnimation->getHeadNode()->_getDerivedPosition(); + Ogre::Vector3 headOffset = mAnimation->getNode("Bip01 Head")->_getDerivedPosition(); headOffset = mNode->convertLocalToWorldPosition(headOffset); mCamera->setPosition(headOffset + mPosition * scale); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 253dbb0ff7..d7620a8de5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -451,9 +451,4 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorgetSkeleton()->getBone("Bip01 Head"); -} - } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index b59051a8d6..224d174f43 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -78,8 +78,6 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); - Ogre::Node* getHeadNode(); - void forceUpdate() { updateParts(true); } }; From a5c868c9f58c26210da7f818fd4449acb7a9a7e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 14:54:19 +0200 Subject: [PATCH 1003/1483] Create a separate vertex buffer for each UV set --- components/nifogre/ogrenifloader.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8f9d69f6e2..a94f469010 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -992,17 +992,19 @@ class NIFMeshLoader : Ogre::ManualResourceLoader 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++) { + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + 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, + + vbuf->writeData(0, elemSize*srcVerts.size(), &uvlist[0], true); + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + bind->setBinding(nextBuf++, vbuf); } - bind->setBinding(nextBuf++, vbuf); } // Triangle faces From 343e2027af0797db178967ca36765d26373ac138 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 15:17:30 +0200 Subject: [PATCH 1004/1483] Support NIF detail maps --- components/nifogre/ogrenifloader.cpp | 15 ++++++++++++++- files/materials/objects.mat | 16 +++++++++++++--- files/materials/objects.shader | 17 +++++++++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a94f469010..9244ac6ccc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -749,16 +749,29 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) { instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); } + if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) + { + instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) + { + // force automips on normal maps for now + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); + } + for(int i = 1;i < 7;i++) { - if(!texName[i].empty()) + if(!texName[i].empty() && (i == Nif::NiTexturingProperty::DarkTexture || i == Nif::NiTexturingProperty::DecalTexture + || i == Nif::NiTexturingProperty::GlossTexture)) warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); } diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 49df4e3949..994a18ea94 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -9,9 +9,10 @@ material openmw_objects_base normalMap emissiveMap use_emissive_map false + use_detail_map false emissiveMapUVSet 0 + detailMapUVSet 0 - is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default depth_write default depth_check default @@ -26,10 +27,11 @@ material openmw_objects_base shader_properties { vertexcolor_mode $vertmode - is_transparent $is_transparent normalMap $normalMap emissiveMapUVSet $emissiveMapUVSet + detailMapUVSet $detailMapUVSet emissiveMap $emissiveMap + detailMap $detailMap } diffuse $diffuse @@ -51,7 +53,7 @@ material openmw_objects_base texture_unit normalMap { - direct_texture $normalMap + texture $normalMap } texture_unit emissiveMap @@ -61,6 +63,14 @@ material openmw_objects_base direct_texture $emissiveMap tex_coord_set $emissiveMapUVSet } + + texture_unit detailMap + { + create_in_ffp $use_detail_map + colour_op_ex modulate_x2 src_current src_texture + direct_texture $detailMap + tex_coord_set $detailMapUVSet + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index d0e8173733..aa7f006a22 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -16,9 +16,10 @@ #define NORMAL_MAP @shPropertyHasValue(normalMap) #define EMISSIVE_MAP @shPropertyHasValue(emissiveMap) +#define DETAIL_MAP @shPropertyHasValue(detailMap) // right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more -#define SECOND_UV_SET @shPropertyString(emissiveMapUVSet) +#define SECOND_UV_SET (@shPropertyString(emissiveMapUVSet) || @shPropertyString(detailMapUVSet)) // if normal mapping is enabled, we force pixel lighting #define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) @@ -236,6 +237,10 @@ shSampler2D(emissiveMap) #endif +#if DETAIL_MAP + shSampler2D(detailMap) +#endif + shInput(float4, UV) #if NORMAL_MAP @@ -313,6 +318,14 @@ { shOutputColour(0) = shSample(diffuseMap, UV.xy); +#if DETAIL_MAP +#if @shPropertyString(detailMapUVSet) + shOutputColour(0) *= shSample(detailMap, UV.zw)*2; +#else + shOutputColour(0) *= shSample(detailMap, UV.xy)*2; +#endif +#endif + #if NORMAL_MAP float3 normal = normalPassthrough; float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); @@ -419,7 +432,7 @@ #endif #if EMISSIVE_MAP - #if SECOND_UV_SET + #if @shPropertyString(emissiveMapUVSet) shOutputColour(0).xyz += shSample(emissiveMap, UV.zw).xyz; #else shOutputColour(0).xyz += shSample(emissiveMap, UV.xy).xyz; From a7de870a443bb602ea45515f312ed730f46045b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 16:21:18 +0200 Subject: [PATCH 1005/1483] Fix mercenary not updating its profit when item was dragged onto the player avatar --- apps/openmw/mwgui/inventorywindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 001f42bd11..c744fcf6d9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -150,6 +150,7 @@ namespace MWGui it = invStore.add(ptr); (*it).getRefData().setCount(mDragAndDrop->mDraggedCount); ptr = *it; + mDragAndDrop->mDraggedFrom->notifyItemDragged(ptr, -mDragAndDrop->mDraggedCount); } /// \todo scripts From d0bcf830919ec034f40f213404be618bc588fefc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 16:30:18 +0200 Subject: [PATCH 1006/1483] Adjust player position to ground after using travel services --- apps/openmw/mwgui/travelwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 465f588b8a..2508498fa0 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -156,6 +156,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->advanceTime(time); } MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); + MWWorld::Class::get(player).adjustPosition(player); mWindowManager.removeGuiMode(GM_Travel); mWindowManager.removeGuiMode(GM_Dialogue); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0); From 50932a7a6bf52281aaa37242e53d0d84739a80ac Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 17:50:03 +0200 Subject: [PATCH 1007/1483] Finished bugfix #691 --- apps/openmw/mwclass/armor.cpp | 47 ++++++++++++++------------------ apps/openmw/mwclass/clothing.cpp | 31 ++++++++++++--------- apps/openmw/mwclass/weapon.cpp | 42 +++++++--------------------- 3 files changed, 49 insertions(+), 71 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 496e695450..f6392941d6 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -321,15 +321,10 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { + std::vector parts = it->get()->mBase->mParts.mParts; + if(*slot == MWWorld::InventoryStore::Slot_Helmet) { - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - - bool allow = true; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_Head) @@ -337,41 +332,41 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - allow = false; - break; + return false; } } - - if(!allow) - break; } if (*slot == MWWorld::InventoryStore::Slot_Boots) { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - allow = false; - // Only notify the player, not npcs if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - } - break; + return false; } } - - if(!allow) - return false; } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + return true; } } return true; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 77a7557bf6..318515a7b1 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -267,32 +267,37 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { + std::vector parts = it->get()->mBase->mParts.mParts; + + if(*slot == MWWorld::InventoryStore::Slot_Helmet) + { + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_Head) + { + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); + + return false; + } + } + } + if (*slot == MWWorld::InventoryStore::Slot_Boots) { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - allow = false; - // Only notify the player, not npcs if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); } - break; + + return false; } } - - if(!allow) - return false; } - } } return true; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 51e8130039..a0a8b7e874 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -411,41 +411,19 @@ namespace MWClass { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - } - } - } - if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) - { - MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); } + return true; } - return true; } return false; } From 194ca2584dfced9e807c1c5865eb3b5600a723e0 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 17:53:41 +0200 Subject: [PATCH 1008/1483] Small azura's star fix --- apps/openmw/mwmechanics/enchanting.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d92acdafc0..a38cb0037b 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -53,14 +53,18 @@ namespace MWMechanics bool Enchanting::create() { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); - //Exception for Azura Star, it's not destroyed after enchanting + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + + //Exception for Azura Star, new one will be added after enchanting if(boost::iequals(mSoulGemPtr.get()->mBase->mId, "Misc_SoulGem_Azura")) - mSoulGemPtr.getCellRef().mSoul=""; - else - mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + { + MWWorld::ManualRef azura (MWBase::Environment::get().getWorld()->getStore(), "Misc_SoulGem_Azura"); + MWWorld::Class::get (player).getContainerStore (player).add (azura.getPtr()); + } if(mSelfEnchanting) { @@ -87,7 +91,6 @@ namespace MWMechanics MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); ref.getPtr().getRefData().setCount (mOldItemCount-1); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); if(!mSelfEnchanting) payForEnchantment(); From 23097ac9dc3b0046471bb1ebce1238dc5a97af61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 09:47:03 -0700 Subject: [PATCH 1009/1483] Minor cleanup of NiMorphData --- components/nif/data.hpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 0804b53ae2..bd109041f1 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -398,16 +398,13 @@ struct NiMorphData : public Record { int morphCount = nif->getInt(); int vertCount = nif->getInt(); - nif->getChar(); + /*relative targets?*/nif->getChar(); mMorphs.resize(morphCount); for(int i = 0;i < morphCount;i++) { mMorphs[i].mData.read(nif, true); - - mMorphs[i].mVertices.resize(vertCount); - for(int j = 0;j < vertCount;j++) - mMorphs[i].mVertices[j] = nif->getVector3(); + nif->getVector3s(mMorphs[i].mVertices, vertCount); } } }; From 2f52df22cea1558074457146f67b8e22516e5976 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 19:00:38 +0200 Subject: [PATCH 1010/1483] Bugfix #553 --- apps/openmw/mwgui/journalwindow.cpp | 6 ------ apps/openmw/mwgui/journalwindow.hpp | 1 - apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++++ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index ba39b01012..f33cfd353f 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -114,15 +114,9 @@ MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) //displayLeftText(list.front()); } -void MWGui::JournalWindow::close() -{ - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); -} - void MWGui::JournalWindow::open() { mPageNumber = 0; - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) { book journal; diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cd1ff7ebbd..f68cca46e9 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -16,7 +16,6 @@ namespace MWGui public: JournalWindow(MWBase::WindowManager& parWindowManager); virtual void open(); - virtual void close(); private: void displayLeftText(std::string text); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0ed49cd7f7..c23106be1a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -656,9 +656,15 @@ namespace MWInput bool gameMode = !mWindows.isGuiMode(); if(gameMode) + { + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); mWindows.pushGuiMode(MWGui::GM_Journal); + } else if(mWindows.getMode() == MWGui::GM_Journal) + { + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); mWindows.popGuiMode(); + } // .. but don't touch any other mode. } From 7c22e123f4c6fb37f27f874749096a4b9a8b4558 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 22:10:55 +0200 Subject: [PATCH 1011/1483] Bugfix #691 changes --- apps/openmw/mwclass/armor.cpp | 27 +++++------------ apps/openmw/mwclass/armor.hpp | 3 +- apps/openmw/mwclass/clothing.cpp | 24 ++++------------ apps/openmw/mwclass/clothing.hpp | 3 +- apps/openmw/mwclass/weapon.cpp | 40 +++++++------------------- apps/openmw/mwclass/weapon.hpp | 3 +- apps/openmw/mwworld/actionequip.cpp | 11 +++++-- apps/openmw/mwworld/class.cpp | 4 +-- apps/openmw/mwworld/class.hpp | 4 +-- apps/openmw/mwworld/inventorystore.cpp | 13 +++++++-- 10 files changed, 53 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index f6392941d6..ddab6f7548 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,25 +292,13 @@ namespace MWClass ref->mBase = record; } - bool Armor::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Armor::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - std::string npcRace = npc.get()->mBase->mRace; for (std::vector::const_iterator slot=slots.first.begin(); @@ -321,7 +309,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = it->get()->mBase->mParts.mParts; + std::vector parts = item.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { @@ -332,7 +320,7 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - return false; + return 0; } } } @@ -345,7 +333,7 @@ namespace MWClass { if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - return false; + return 0; } } } @@ -363,13 +351,12 @@ namespace MWClass weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + return 3; } - return true; + return 1; } } - return true; + return 1; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index bb07e42b03..96c72848cc 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 318515a7b1..58c4a2c5c6 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,25 +238,11 @@ namespace MWClass ref->mBase = record; } - bool Clothing::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Clothing::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); - // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - std::string npcRace = npc.get()->mBase->mRace; for (std::vector::const_iterator slot=slots.first.begin(); @@ -267,7 +253,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = it->get()->mBase->mParts.mParts; + std::vector parts = item.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { @@ -278,7 +264,7 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - return false; + return 0; } } } @@ -294,13 +280,13 @@ namespace MWClass MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); } - return false; + return 0; } } } } } - return true; + return 1; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 4978fa2288..eb8d801996 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,7 +61,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a0a8b7e874..a0cacaf6bd 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,48 +384,30 @@ namespace MWClass ref->mBase = record; } - bool Weapon::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Weapon::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); - - // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - - std::string npcRace = npc.get()->mBase->mRace; - // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + if(item.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + item.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + item.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + item.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + return 2; } - return true; + return 1; } } - return false; + return 0; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 922cd165f2..01686b09cc 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,7 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index c147113fc6..51d0de6fe8 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,8 +43,15 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - if(!MWWorld::Class::get(getTarget()).canEquip(actor,getTarget())) - break; + switch(MWWorld::Class::get (*it).canBeEquipped (actor, *it)) + { + case 0: + return; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index ee2072cf09..a0067f5d2e 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,9 +259,9 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - bool Class::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Class::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - return true; + return 1; } void Class::adjustPosition(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 4931da7a86..362a8bc9ca 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,8 +242,8 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; - ///< Return 0 if player cannot equip item. Unequip twohanded item if neccesary + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 7a5ae38d0e..9f51db3534 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -131,6 +131,8 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) { const MWMechanics::NpcStats& stats = MWWorld::Class::get(npc).getNpcStats(npc); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + TSlots slots; initSlots (slots); @@ -184,8 +186,15 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - if(!MWWorld::Class::get (test).canEquip (npc, test)) - continue; + switch(MWWorld::Class::get (test).canBeEquipped (npc, test)) + { + case 0: + continue; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { From e7c0f2a211b4854b6ce6198c5245a6071483b0da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 14:54:13 -0700 Subject: [PATCH 1012/1483] Minor cleanup to loading texture UV coords --- components/nifogre/ogrenifloader.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index aa28a30dd2..bf4621e6f0 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1400,21 +1400,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader // Texture UV coordinates size_t numUVs = data->uvlist.size(); - if(numUVs) + for(size_t i = 0;i < numUVs;i++) { - for(size_t i = 0;i < numUVs;i++) - { - size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); - vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size(), - Ogre::HardwareBuffer::HBU_STATIC); + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), + srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); + vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); - const std::vector &uvlist = data->uvlist[i]; - - vbuf->writeData(0, elemSize*srcVerts.size(), &uvlist[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, - Ogre::VES_TEXTURE_COORDINATES, i); - bind->setBinding(nextBuf++, vbuf); - } + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + bind->setBinding(nextBuf++, vbuf); } // Triangle faces From 973fdeb2e01be028de7e5fa0b3df473c72fce397 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 15:21:28 -0700 Subject: [PATCH 1013/1483] Improve particle system placement when no emitters are specified --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index bf4621e6f0..3c876283e1 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1566,7 +1566,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } if(!partsys->isAttached()) - entitybase->attachObjectToBone(partnode->name, partsys); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partnode->recIndex); + Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); + entitybase->attachObjectToBone(trgtbone->getName(), partsys); + } } catch(std::exception &e) { std::cerr<< "Particles exception: "< Date: Tue, 9 Apr 2013 01:24:17 +0200 Subject: [PATCH 1014/1483] Fix several NPCs spawning in the ground --- apps/openmw/mwworld/scene.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2244a4fc64..439f761311 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -118,6 +118,7 @@ namespace MWWorld float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; + // Load terrain physics first... if (cell->mCell->isExterior()) { ESM::Land* land = @@ -137,6 +138,7 @@ namespace MWWorld } } + // ... then references. This is important for adjustPosition to work correctly. /// \todo rescale depending on the state of a new GMST insertCell (*cell, true); @@ -439,7 +441,6 @@ namespace MWWorld insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics, rescale); - insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics, rescale); @@ -447,11 +448,13 @@ namespace MWWorld insertCellRefList(mRendering, cell.mLights, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics, rescale); - insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics, rescale); + // Load NPCs and creatures _after_ everything else (important for adjustPosition to work correctly) + insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale); } void Scene::addObjectToScene (const Ptr& ptr) From 623c2c8201c80857bbaefe4278b04e88cdda269b Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 07:45:07 +0200 Subject: [PATCH 1015/1483] Minor fix --- apps/openmw/mwworld/actionequip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 51d0de6fe8..d5927b6c55 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,7 +43,7 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (*it).canBeEquipped (actor, *it)) + switch(MWWorld::Class::get (getTarget()).canBeEquipped (actor, getTarget())) { case 0: return; From ec6dff38b187691b809c4b90ac15c27a972d4da2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 11:40:36 +0200 Subject: [PATCH 1016/1483] added basic spell table --- apps/opencs/model/world/data.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadspel.cpp | 10 ++++++++++ components/esm/loadspel.hpp | 3 +++ 9 files changed, 55 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b385c5b4c2..af2b17bd96 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -99,6 +99,13 @@ CSMWorld::Data::Data() mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); + mSpells.addColumn (new StringIdColumn); + mSpells.addColumn (new RecordStateColumn); + mSpells.addColumn (new NameColumn); + mSpells.addColumn (new FlagColumn ("Autocalc", 0x1)); + mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); + mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -109,6 +116,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); + addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); } CSMWorld::Data::~Data() @@ -217,6 +225,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() return mBirthsigns; } +const CSMWorld::IdCollection& CSMWorld::Data::getSpells() const +{ + return mSpells; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSpells() +{ + return mSpells; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -261,6 +279,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SCPT: mScripts.load (reader, base); break; case ESM::REC_REGN: mRegions.load (reader, base); break; case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; + case ESM::REC_SPEL: mSpells.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 122e855d86..d7b69ba5e3 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -36,6 +37,7 @@ namespace CSMWorld IdCollection mScripts; IdCollection mRegions; IdCollection mBirthsigns; + IdCollection mSpells; std::vector mModels; std::map mModelIndex; @@ -92,6 +94,10 @@ namespace CSMWorld IdCollection& getBirthsigns(); + const IdCollection& getSpells() const; + + IdCollection& getSpells(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6d305d6c0f..11f4877886 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -27,6 +27,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -43,6 +44,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 0586719f14..5586b22e79 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -53,7 +53,9 @@ namespace CSMWorld Type_Regions, Type_Region, Type_Birthsigns, - Type_Birthsign + Type_Birthsign, + Type_Spells, + Type_Spell }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index af9b814203..dfdcb10365 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -121,6 +121,10 @@ void CSVDoc::View::setupWorldMenu() QAction *birthsigns = new QAction (tr ("Birthsigns"), this); connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView())); world->addAction (birthsigns); + + QAction *spells = new QAction (tr ("Spells"), this); + connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); + world->addAction (spells); } void CSVDoc::View::setupUi() @@ -316,6 +320,11 @@ void CSVDoc::View::addBirthsignsSubView() addSubView (CSMWorld::UniversalId::Type_Birthsigns); } +void CSVDoc::View::addSpellsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Spells); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 12944e5693..9241efbb9a 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -131,6 +131,8 @@ namespace CSVDoc void addRegionsSubView(); void addBirthsignsSubView(); + + void addSpellsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 23c66319c6..c9ef4df8db 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -24,6 +24,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, + CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index b0f1ca64b9..8149fe4cef 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -20,4 +20,14 @@ void Spell::save(ESMWriter &esm) mEffects.save(esm); } + void Spell::blank() + { + mData.mType = 0; + mData.mCost = 0; + mData.mFlags = 0; + + mName.clear(); + + mEffects.mList.clear(); + } } diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 0d5e0be522..3a620962d1 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -43,6 +43,9 @@ struct Spell void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From ae0a7d5bcde2e15b228b388f9e693b1453378a36 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 11:53:47 +0200 Subject: [PATCH 1017/1483] added cost and type columns to spell table --- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 48 ++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 2 ++ apps/opencs/view/doc/viewmanager.cpp | 8 +++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 5c2ce8a676..23049164f8 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -34,7 +34,8 @@ namespace CSMWorld Display_GlobalVarType, Display_Specialisation, Display_Attribute, - Display_Boolean + Display_Boolean, + Display_SpellType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fbc533779a..6d6d1b1ef0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -675,6 +675,54 @@ namespace CSMWorld return true; } }; + + template + struct SpellTypeColumn : public Column + { + SpellTypeColumn() : Column ("Type", ColumnBase::Display_SpellType) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mType; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mType = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct CostColumn : public Column + { + CostColumn() : Column ("Cost", ColumnBase::Display_Integer) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mCost; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + record2.mData.mCost = data.toInt(); + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index af2b17bd96..84b49b6bcd 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -102,6 +102,8 @@ CSMWorld::Data::Data() mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); mSpells.addColumn (new NameColumn); + mSpells.addColumn (new SpellTypeColumn); + mSpells.addColumn (new CostColumn); mSpells.addColumn (new FlagColumn ("Autocalc", 0x1)); mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 3be7228b31..050bd51fe2 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -49,6 +49,11 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) "Luck", 0 }; + static const char *sSpellTypes[] = + { + "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0 + }; + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -62,6 +67,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, new CSVWorld::EnumDelegateFactory (sAttributes, true)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType, + new CSVWorld::EnumDelegateFactory (sSpellTypes)); } CSVDoc::ViewManager::~ViewManager() From 40bb772e34aedf01c472aad93147c3a81a5a983d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 12:44:49 +0200 Subject: [PATCH 1018/1483] added verifier for spell record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/spellcheck.cpp | 35 ++++++++++++++++++++++++++ apps/opencs/model/tools/spellcheck.hpp | 29 +++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/spellcheck.cpp create mode 100644 apps/opencs/model/tools/spellcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 87221d7af5..76d4280c8f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -36,7 +36,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck + birthsigncheck spellcheck ) diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp new file mode 100644 index 0000000000..3adee0a4ef --- /dev/null +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -0,0 +1,35 @@ + +#include "spellcheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SpellCheckStage::SpellCheckStage (const CSMWorld::IdCollection& spells) +: mSpells (spells) +{} + +int CSMTools::SpellCheckStage::setup() +{ + return mSpells.getSize(); +} + +void CSMTools::SpellCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Spell& spell = mSpells.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Spell, spell.mId); + + // test for empty name and description + if (spell.mName.empty()) + messages.push_back (id.toString() + "|" + spell.mId + " has an empty name"); + + // test for invalid cost values + if (spell.mData.mCost<0) + messages.push_back (id.toString() + "|" + spell.mId + " has a negative spell costs"); + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/spellcheck.hpp b/apps/opencs/model/tools/spellcheck.hpp new file mode 100644 index 0000000000..0566392193 --- /dev/null +++ b/apps/opencs/model/tools/spellcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SPELLCHECK_H +#define CSM_TOOLS_SPELLCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that spell records are internally consistent + class SpellCheckStage : public Stage + { + const CSMWorld::IdCollection& mSpells; + + public: + + SpellCheckStage (const CSMWorld::IdCollection& spells); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 78796de418..803861203c 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -19,6 +19,7 @@ #include "soundcheck.hpp" #include "regioncheck.hpp" #include "birthsigncheck.hpp" +#include "spellcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -72,6 +73,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); + + mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); } return mVerifier; From be4a01bdb4edf99ca9618ea477f31f44366fc85e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 14:27:32 +0200 Subject: [PATCH 1019/1483] added missing recrod type columns --- apps/opencs/model/world/data.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 84b49b6bcd..14aff47e89 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -33,11 +33,13 @@ CSMWorld::Data::Data() mGmsts.addColumn (new StringIdColumn); mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); + mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Skill)); mSkills.addColumn (new AttributeColumn); mSkills.addColumn (new SpecialisationColumn); for (int i=0; i<4; ++i) @@ -46,6 +48,7 @@ CSMWorld::Data::Data() mClasses.addColumn (new StringIdColumn); mClasses.addColumn (new RecordStateColumn); + mClasses.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Class)); mClasses.addColumn (new NameColumn); mClasses.addColumn (new AttributesColumn (0)); mClasses.addColumn (new AttributesColumn (1)); @@ -59,6 +62,7 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); + mFactions.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Faction)); mFactions.addColumn (new NameColumn); mFactions.addColumn (new AttributesColumn (0)); mFactions.addColumn (new AttributesColumn (1)); @@ -68,6 +72,7 @@ CSMWorld::Data::Data() mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); + mRaces.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Race)); mRaces.addColumn (new NameColumn); mRaces.addColumn (new DescriptionColumn); mRaces.addColumn (new FlagColumn ("Playable", 0x1)); @@ -79,6 +84,7 @@ CSMWorld::Data::Data() mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); + mSounds.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Sound)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); @@ -86,21 +92,25 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); + mScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Script)); mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); + mRegions.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Region)); mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); + mBirthsigns.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Birthsign)); mBirthsigns.addColumn (new NameColumn); mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); + mSpells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Spell)); mSpells.addColumn (new NameColumn); mSpells.addColumn (new SpellTypeColumn); mSpells.addColumn (new CostColumn); From cd33f40c8fb1497b3db6eae569a45a9c334cf9d4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 14:28:31 +0200 Subject: [PATCH 1020/1483] re-enabled opening of record subviews via double click in table --- apps/opencs/view/world/tablesubview.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index f4deceb490..bb4bb76c61 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -21,6 +21,5 @@ void CSVWorld::TableSubView::setEditLock (bool locked) void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) { - /// \todo re-enable, after dialogue sub views have been fixed up -// focusId (mTable->getUniversalId (index.row())); + focusId (mTable->getUniversalId (index.row())); } \ No newline at end of file From 46925e93a6f79402f0838eabab30f02c4352a828 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 16:14:08 +0200 Subject: [PATCH 1021/1483] Second minor fix --- apps/openmw/mwclass/armor.cpp | 3 +++ apps/openmw/mwworld/actionequip.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index ddab6f7548..a14b2667e1 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -343,6 +343,9 @@ namespace MWClass { MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if(weapon == invStore.end()) + return 1; + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index d5927b6c55..82431ac8f3 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -18,6 +18,7 @@ namespace MWWorld void ActionEquip::executeImp (const Ptr& actor) { + MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); // slots that this item can be equipped in @@ -27,7 +28,7 @@ namespace MWWorld MWWorld::ContainerStoreIterator it = invStore.begin(); for (; it != invStore.end(); ++it) { - if (*it == getTarget()) + if (*it == object) { break; } @@ -43,7 +44,7 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (getTarget()).canBeEquipped (actor, getTarget())) + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) { case 0: return; @@ -70,10 +71,10 @@ namespace MWWorld } } - std::string script = MWWorld::Class::get(*it).getScript(*it); + std::string script = MWWorld::Class::get(object).getScript(object); /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") - (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); + (object).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); } } From 9f9d978b0f1020777403f2b5f2e67b7ed0a03cd7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 09:07:05 -0700 Subject: [PATCH 1022/1483] Use an enum to specify the NPC's view mode (normal, head only) --- apps/openmw/mwrender/characterpreview.cpp | 8 ++++---- apps/openmw/mwrender/npcanimation.cpp | 8 ++++---- apps/openmw/mwrender/npcanimation.hpp | 10 ++++++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 616543a7d4..0da20f3daf 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -59,8 +59,8 @@ namespace MWRender mNode = renderRoot->createChildSceneNode(); - mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), + 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); mNode->setVisible (false); @@ -101,8 +101,8 @@ namespace MWRender assert(mAnimation); delete mAnimation; - mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), + 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); float scale=1.f; MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d7620a8de5..685edb68c8 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -56,7 +56,7 @@ NpcAnimation::~NpcAnimation() } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, ViewMode viewMode) : Animation(ptr), mStateID(-1), mTimeToChange(0), @@ -73,7 +73,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mGloveL(inv.end()), mGloveR(inv.end()), mSkirtIter(inv.end()), - mHeadOnly(headOnly) + mViewMode(viewMode) { mNpc = mPtr.get()->mBase; @@ -222,7 +222,7 @@ void NpcAnimation::updateParts(bool forceupdate) if(!forceupdate) return; - for(size_t i = 0;i < slotlistsize && !mHeadOnly;i++) + for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); @@ -259,7 +259,7 @@ void NpcAnimation::updateParts(bool forceupdate) if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); - if (mHeadOnly) + if(mViewMode == VM_HeadOnly) return; static const struct { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 224d174f43..44639e94ab 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -26,6 +26,11 @@ struct PartInfo { const char name[32]; }; +enum ViewMode { + VM_Normal, + VM_HeadOnly +}; + private: static const size_t sPartListSize = 27; static const PartInfo sPartList[sPartListSize]; @@ -39,7 +44,7 @@ private: std::string mHeadModel; std::string mHairModel; std::string mBodyPrefix; - bool mHeadOnly; + ViewMode mViewMode; float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; @@ -73,7 +78,8 @@ private: public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly=false); + MWWorld::InventoryStore& inv, int visibilityFlags, + ViewMode viewMode=VM_Normal); virtual ~NpcAnimation(); virtual Ogre::Vector3 runAnimation(float timepassed); From 029d56572777fcccf01639166af528b63c2837e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 09:23:07 -0700 Subject: [PATCH 1023/1483] Avoid calling setVisible for character previews --- apps/openmw/mwrender/characterpreview.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 0da20f3daf..8396acaea8 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -62,8 +62,6 @@ namespace MWRender mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - mNode->setVisible (false); - Ogre::Vector3 scale = mNode->getScale(); mCamera->setPosition(mPosition * scale); mCamera->lookAt(mLookAt * scale); @@ -108,8 +106,6 @@ namespace MWRender MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); mNode->setScale(Ogre::Vector3(scale)); - mNode->setVisible (false); - mCamera->setPosition(mPosition * mNode->getScale()); mCamera->lookAt(mLookAt * mNode->getScale()); @@ -139,12 +135,8 @@ namespace MWRender mNode->setOrientation (Ogre::Quaternion::IDENTITY); - mNode->setVisible (true); - mRenderTarget->update(); mSelectionBuffer->update(); - - mNode->setVisible (false); } int InventoryPreview::getSlotSelected (int posX, int posY) @@ -178,9 +170,7 @@ namespace MWRender updateCamera(); - mNode->setVisible (true); mRenderTarget->update(); - mNode->setVisible (false); } void RaceSelectionPreview::setPrototype(const ESM::NPC &proto) From 44ef02eb99c2cf7f4cab6d60320e155fe5183579 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:04:59 +0200 Subject: [PATCH 1024/1483] Third minor fix --- apps/openmw/mwworld/actionequip.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 82431ac8f3..2877a2c5ae 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -40,19 +40,20 @@ namespace MWWorld bool equipped = false; + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + { + case 0: + return; //Item cannot be equipped, so function breaks. + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) - { - case 0: - return; - case 2: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - case 3: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) From 248fff6eb7323b7c7cf4f56afff53c1b820e6fb3 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:41:03 +0200 Subject: [PATCH 1025/1483] Fourth minor fix --- apps/openmw/mwworld/actionequip.cpp | 4 +++- apps/openmw/mwworld/inventorystore.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 2877a2c5ae..39c5abe345 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,11 +43,13 @@ namespace MWWorld switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) { case 0: - return; //Item cannot be equipped, so function breaks. + return; case 2: invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; case 3: invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; } // equip the item in the first free slot diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 9f51db3534..782e3f920f 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -192,8 +192,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) continue; case 2: invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; case 3: invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; } if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped From bd93e63150dc69c0e3caf27231dfbede99772baf Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:46:27 +0200 Subject: [PATCH 1026/1483] Fifth minor fix --- apps/openmw/mwworld/actionequip.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 39c5abe345..fd35d0dd3c 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -21,6 +21,18 @@ namespace MWWorld MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + { + case 0: + return; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; + } + // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(getTarget()).getEquipmentSlots(getTarget()); @@ -40,18 +52,6 @@ namespace MWWorld bool equipped = false; - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) - { - case 0: - return; - case 2: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - break; - case 3: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - break; - } - // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) From 6ca2b1af743b659e44b9601f99c985a92a66e99a Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Tue, 9 Apr 2013 19:24:41 +0100 Subject: [PATCH 1027/1483] fix for turning animations playing when in vanity mode --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 13 +++++++++++-- apps/openmw/mwrender/renderingmanager.cpp | 10 ++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 040dc703c0..39e985890a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -319,6 +319,7 @@ namespace MWBase virtual void allowVanityMode(bool allow) = 0; virtual void togglePlayerLooking(bool enable) = 0; virtual void changeVanityModeScale(float factor) = 0; + virtual bool vanityRotateCamera(float * rot) = 0; virtual void renderPlayer() = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c23106be1a..6a34161e08 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -533,8 +533,17 @@ namespace MWInput float scale = MWBase::Environment::get().getFrameDuration(); if(scale <= 0.0f) scale = 1.0f; - mPlayer.setYaw(x/scale); - mPlayer.setPitch(-y/scale); + float rot[3]; + rot[0] = -y; + rot[1] = 0.0f; + rot[2] = x; + + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer.setYaw(x/scale); + mPlayer.setPitch(-y/scale); + } if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index cd5ab19b9d..029cf394b4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -891,6 +891,16 @@ void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float mPlayer->getSightAngles(pitch, yaw); } +bool RenderingManager::vanityRotateCamera(float* rot) +{ + if(!mPlayer->isVanityOrPreviewModeEnabled()) + return false; + + Ogre::Vector3 vRot(rot); + mPlayer->rotateCamera(vRot, true); + return true; +} + void RenderingManager::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) { return mLocalMap->getInteriorMapPosition (position, nX, nY, x, y); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b343a60bdb..cece7a95f0 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -88,6 +88,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList mPlayer->setCameraDistance(-factor/120.f*10, true, true); } + bool vanityRotateCamera(float* rot); + void getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw); void attachCameraTo(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ae9b7a06b7..11ccd8f2fc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1364,6 +1364,11 @@ namespace MWWorld return physactor && physactor->getOnGround(); } + bool World::vanityRotateCamera(float * rot) + { + return mRendering->vanityRotateCamera(rot); + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5ae87a1ff7..7b12babee9 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -361,6 +361,8 @@ namespace MWWorld mRendering->changeVanityModeScale(factor); } + virtual bool vanityRotateCamera(float * rot); + virtual void renderPlayer(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); From 0e7d555cdf5ebd475792ffe13c0ad7d653288267 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Apr 2013 20:31:00 +0200 Subject: [PATCH 1028/1483] Terrain material now uses multiple passes if required, which means it can support an arbitrary number of layers. Also re-enables PSSM. --- apps/openmw/mwgui/settingswindow.cpp | 4 +- apps/openmw/mwrender/shadows.cpp | 5 +- apps/openmw/mwrender/terrainmaterial.cpp | 161 ++++++++++++++++------- apps/openmw/mwrender/terrainmaterial.hpp | 3 + files/materials/shadowcaster.shader | 3 +- files/materials/terrain.shader | 33 ++++- 6 files changed, 148 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 58754472dd..5fb6e5000b 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -236,9 +236,7 @@ namespace MWGui mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); - //mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); - mShadowsLargeDistance->setCaptionWithReplacing("#{sOff}"); - mShadowsLargeDistance->setEnabled (false); + mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); mShadowsEnabledButton->setCaptionWithReplacing(Settings::Manager::getBool("enabled", "Shadows") ? "#{sOn}" : "#{sOff}"); mActorShadows->setCaptionWithReplacing(Settings::Manager::getBool("actor shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 595a82294b..0d066a0ecb 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -28,10 +28,7 @@ void Shadows::recreate() { bool enabled = Settings::Manager::getBool("enabled", "Shadows"); - // Split shadow maps are currently disabled because the terrain cannot cope with them - // (Too many texture units) Solution would be a multi-pass terrain material - //bool split = Settings::Manager::getBool("split", "Shadows"); - const bool split = false; + bool split = Settings::Manager::getBool("split", "Shadows"); sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false"); diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 8a568883df..dd74254be6 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -68,59 +68,113 @@ namespace MWRender Ogre::MaterialManager::getSingleton().remove(matName); mMaterial = sh::Factory::getInstance().createMaterialInstance (matName); - mMaterial->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); - sh::MaterialInstancePass* p = mMaterial->createPass (); + int numPasses = getRequiredPasses(terrain); + int maxLayersInOnePass = getMaxLayersPerPass(terrain); - p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); - p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); - - p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap))); - - // global colour map - sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap"); - colourMap->setProperty ("texture_alias", sh::makeProperty (new sh::StringValue(mMaterial->getName() + "_colourMap"))); - colourMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - - // global normal map - sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap"); - normalMap->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getTerrainNormalMap ()->getName()))); - normalMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - - Ogre::uint maxLayers = getMaxLayers(terrain); - Ogre::uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount()); - Ogre::uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - - p->mShaderProperties.setProperty ("num_layers", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numLayers)))); - p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); - - // blend maps - for (Ogre::uint i = 0; i < numBlendTextures; ++i) + for (int pass=0; passcreateTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); - blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(i)))); - blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - } + int layerOffset = maxLayersInOnePass * pass; + int blendmapOffset = (pass == 0) ? 1 : 0; // the first layer of the first pass is the base layer and does not need a blend map - // layer maps - for (Ogre::uint i = 0; i < numLayers; ++i) - { - sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); - diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(i, 0)))); - p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), - sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(int((i-1) / 4)) + "." + getComponent(int((i-1) % 4))))); - } + sh::MaterialInstancePass* p = mMaterial->createPass (); - // shadow - for (Ogre::uint i = 0; i < 3; ++i) - { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); - } + p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); + p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); + if (pass != 0) + { + p->setProperty ("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); + // Only write if depth is equal to the depth value written by the previous pass. + p->setProperty ("depth_func", sh::makeProperty(new sh::StringValue("equal"))); + } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty(new sh::StringValue( - Ogre::StringConverter::toString(numBlendTextures + numLayers + 2)))); + p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap))); + p->mShaderProperties.setProperty ("is_first_pass", sh::makeProperty(new sh::BooleanValue(pass == 0))); + + // global colour map + sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap"); + colourMap->setProperty ("texture_alias", sh::makeProperty (new sh::StringValue(mMaterial->getName() + "_colourMap"))); + colourMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + // global normal map + sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap"); + normalMap->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getTerrainNormalMap ()->getName()))); + normalMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + Ogre::uint numLayersInThisPass = std::min(maxLayersInOnePass, terrain->getLayerCount()-layerOffset); + + // HACK: Terrain::getLayerBlendTextureIndex should be const, but it is not. + // Remove this once ogre got fixed. + Ogre::Terrain* nonconstTerrain = const_cast(terrain); + + // a blend map might be shared between two passes + // so we can't just use terrain->getBlendTextureCount() + Ogre::uint numBlendTextures=0; + std::vector blendTextures; + for (unsigned int layer=blendmapOffset; layergetBlendTextureName(nonconstTerrain->getLayerBlendTextureIndex( + static_cast(layerOffset+layer)).first); + if (std::find(blendTextures.begin(), blendTextures.end(), blendTextureName) == blendTextures.end()) + { + blendTextures.push_back(blendTextureName); + ++numBlendTextures; + } + } + + p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass)))); + p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); + + // blend maps + // the index of the first blend map used in this pass + int blendmapStart; + if (terrain->getLayerCount() == 1) // special case. if there's only one layer, we don't need blend maps at all + blendmapStart = 0; + else + blendmapStart = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+blendmapOffset)).first; + for (Ogre::uint i = 0; i < numBlendTextures; ++i) + { + sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); + blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(blendmapStart+i)))); + blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + } + + // layer maps + for (Ogre::uint i = 0; i < numLayersInThisPass; ++i) + { + sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); + diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(layerOffset+i, 0)))); + + if (i+layerOffset > 0) + { + int blendTextureIndex = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+i)).first; + int blendTextureComponent = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+i)).second; + p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), + sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(blendTextureIndex-blendmapStart) + "." + getComponent(blendTextureComponent)))); + } + else + { + // just to make it shut up about blendmap_component_0 not existing in the first pass. + // it might be retrieved, but will never survive the preprocessing step. + p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), + sh::makeProperty (new sh::StringValue(""))); + } + } + + // shadow + for (Ogre::uint i = 0; i < 3; ++i) + { + sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); + shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + } + + p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( + Ogre::StringConverter::toString(numBlendTextures + numLayersInThisPass + 2)))); + + // make sure the pass index is fed to the permutation handler, because blendmap components may be different + p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(pass))); + } return Ogre::MaterialManager::getSingleton().getByName(matName); } @@ -142,6 +196,11 @@ namespace MWRender } Ogre::uint8 TerrainMaterial::Profile::getMaxLayers(const Ogre::Terrain* terrain) const + { + return 255; + } + + int TerrainMaterial::Profile::getMaxLayersPerPass (const Ogre::Terrain* terrain) { // count the texture units free Ogre::uint8 freeTextureUnits = 16; @@ -151,11 +210,21 @@ namespace MWRender --freeTextureUnits; // shadow --freeTextureUnits; + --freeTextureUnits; + --freeTextureUnits; // each layer needs 1.25 units (1xdiffusespec, 0.25xblend) return static_cast(freeTextureUnits / (1.25f)); } + int TerrainMaterial::Profile::getRequiredPasses (const Ogre::Terrain* terrain) + { + int maxLayersPerPass = getMaxLayersPerPass(terrain); + assert(terrain->getLayerCount()); + assert(maxLayersPerPass); + return std::ceil(static_cast(terrain->getLayerCount()) / maxLayersPerPass); + } + void TerrainMaterial::Profile::updateParams(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain) { } diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index fe1214cf5e..c90499baeb 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -72,6 +72,9 @@ namespace MWRender private: sh::MaterialInstance* mMaterial; + int getRequiredPasses (const Ogre::Terrain* terrain); + int getMaxLayersPerPass (const Ogre::Terrain* terrain); + bool mGlobalColourMap; }; diff --git a/files/materials/shadowcaster.shader b/files/materials/shadowcaster.shader index b312d414c5..b992366a7e 100644 --- a/files/materials/shadowcaster.shader +++ b/files/materials/shadowcaster.shader @@ -45,8 +45,7 @@ // use alpha channel of the first texture float alpha = shSample(texture1, UV).a; - // discard if alpha is less than 0.5 - if (alpha < 1.0) + if (alpha < 0.5) discard; #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index c73b582f8d..de90a6cf61 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -1,6 +1,6 @@ #include "core.h" -#define IS_FIRST_PASS 1 +#define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) #define FOG @shGlobalSettingBool(fog) @@ -23,6 +23,9 @@ #define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) +#if !IS_FIRST_PASS +// This is not the first pass. +#endif #if NEED_DEPTH @shAllocatePassthrough(1, depth) @@ -222,7 +225,11 @@ float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif - + +#if !IS_FIRST_PASS +float combinedAlpha = 0.f; +#endif + // Layer calculations @shForeach(@shPropertyString(num_blendmaps)) float4 blendValues@shIterator = shSample(blendMap@shIterator, UV); @@ -232,12 +239,20 @@ @shForeach(@shPropertyString(num_layers)) -#if IS_FIRST_PASS == 1 && @shIterator == 0 - // first layer of first pass doesn't need a blend map +#if IS_FIRST_PASS + #if @shIterator == 0 + // first layer of first pass is the base layer and doesn't need a blend map albedo = shSample(diffuseMap0, UV * 10).rgb; -#else + #else albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); - + #endif +#else + #if @shIterator == 0 + albedo = shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator); + #else + albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); + #endif + combinedAlpha += blendValues@shPropertyString(blendmap_component_@shIterator); #endif @shEndForeach @@ -325,6 +340,12 @@ // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); + +#if IS_FIRST_PASS + shOutputColour(0).a = 1; +#else + shOutputColour(0).a = min(combinedAlpha, 1.f); +#endif } #endif From a700c50e84e06586e3a766940e43f33e156d67ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 15:10:14 -0700 Subject: [PATCH 1029/1483] Add a first-person view mode to NpcAnimation And use it instead of showing/hiding the player. --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 64 ++++++++++++++++++++++----- apps/openmw/mwrender/npcanimation.hpp | 3 ++ apps/openmw/mwrender/player.cpp | 12 +++-- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 067e856720..a849b20efe 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -476,7 +476,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con Ogre::Vector3 Animation::runAnimation(float timepassed) { - Ogre::Vector3 movement = Ogre::Vector3::ZERO; + Ogre::Vector3 movement(0.0f); timepassed *= mAnimSpeedMult; while(mCurrentAnim && mPlaying) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 685edb68c8..7e59f8f6c9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -130,7 +130,40 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); setAnimationSources(skelnames); - updateParts(true); + forceUpdate(); +} + +void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) +{ + assert(viewMode != VM_HeadOnly); + mViewMode = viewMode; + + /* FIXME: Enable this once first-person animations work. */ +#if 0 + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mNpc->mRace); + + bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; + std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); + + std::vector skelnames(1, smodel); + if(!mNpc->isMale() && !isBeast) + skelnames.push_back("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + skelnames.push_back("meshes\\argonian_swimkna.nif"); + if(mNpc->mModel.length() > 0) + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + if(mViewMode == VM_FirstPerson) + { + smodel = (!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif"); + skelnames.push_back(smodel); + } + setAnimationSources(skelnames); +#endif + + for(size_t i = 0;i < sPartListSize;i++) + removeIndividualPart(i); + forceUpdate(); } void NpcAnimation::updateParts(bool forceupdate) @@ -254,13 +287,18 @@ void NpcAnimation::updateParts(bool forceupdate) reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio); } - if(mPartPriorities[ESM::PRT_Head] < 1) - addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); - if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) - addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); - + if(mViewMode != VM_FirstPerson) + { + if(mPartPriorities[ESM::PRT_Head] < 1) + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); + if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); + } if(mViewMode == VM_HeadOnly) return; + /* FIXME: Remove this once we figure out how to show what in first-person */ + if(mViewMode == VM_FirstPerson) + return; static const struct { ESM::PartReferenceType type; @@ -288,6 +326,7 @@ void NpcAnimation::updateParts(bool forceupdate) { ESM::PRT_Tail, { "tail", "" } } }; + const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) { @@ -298,14 +337,14 @@ void NpcAnimation::updateParts(bool forceupdate) if(!mNpc->isMale()) { - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]+ext); if(part == 0) - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]+ext); } if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]+ext); if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]+ext); if(part) addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); @@ -431,6 +470,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts) { + const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; for(std::size_t i = 0; i < parts.size(); i++) { const ESM::PartReference &part = parts[i]; @@ -440,9 +480,9 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorisMale()) - bodypart = partStore.search(part.mFemale); + bodypart = partStore.search(part.mFemale+ext); if(!bodypart) - bodypart = partStore.search(part.mMale); + bodypart = partStore.search(part.mMale+ext); if(bodypart) addOrReplaceIndividualPart(part.mPart, group, priority, "meshes\\"+bodypart->mModel); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 44639e94ab..f2f4c66697 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -28,6 +28,7 @@ struct PartInfo { enum ViewMode { VM_Normal, + VM_FirstPerson, VM_HeadOnly }; @@ -84,6 +85,8 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); + void setViewMode(ViewMode viewMode); + void forceUpdate() { updateParts(true); } }; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 55fda326fa..439264f3af 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -124,8 +124,6 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - /// \fixme We shouldn't hide the whole model, just certain components of the character (head, chest, feet, etc) - mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); if (mFirstPersonView && !mVanity.enabled) { return; } @@ -139,6 +137,8 @@ namespace MWRender void Player::toggleViewMode() { mFirstPersonView = !mFirstPersonView; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); if (mFirstPersonView) { mCamera->setPosition(0.f, 0.f, 0.f); setLowHeight(false); @@ -168,6 +168,9 @@ namespace MWRender mVanity.enabled = enable; mVanity.forced = force && enable; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + float offset = mPreviewCam.offset; Ogre::Vector3 rot(0.f, 0.f, 0.f); if (mVanity.enabled) { @@ -194,6 +197,8 @@ namespace MWRender return; } mPreviewMode = enable; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); float offset = mCamera->getPosition().z; if (mPreviewMode) { mMainCam.offset = offset; @@ -305,7 +310,8 @@ namespace MWRender delete mAnimation; mAnimation = anim; - mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); } void Player::setHeight(float height) From 50d8353a8db9bdeb5f577449e7ae784a3f15bd70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 16:51:04 -0700 Subject: [PATCH 1030/1483] Fix a hack so arms dont show in first-person --- apps/openmw/mwrender/npcanimation.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7e59f8f6c9..96220f47d0 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -255,6 +255,14 @@ void NpcAnimation::updateParts(bool forceupdate) if(!forceupdate) return; + /* FIXME: Remove this once we figure out how to show what in first-person */ + if(mViewMode == VM_FirstPerson) + { + for(size_t i = 0;i < slotlistsize;i++) + this->*slotlist[i].part = inv.getSlot(slotlist[i].slot); + return; + } + for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); @@ -296,9 +304,6 @@ void NpcAnimation::updateParts(bool forceupdate) } if(mViewMode == VM_HeadOnly) return; - /* FIXME: Remove this once we figure out how to show what in first-person */ - if(mViewMode == VM_FirstPerson) - return; static const struct { ESM::PartReferenceType type; From ce9bc6d9bae9d03b8c614e781b420789eb9531d4 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 00:32:05 -0400 Subject: [PATCH 1031/1483] MwGui windowManager calls fixed to use MWBase::Environment::get().getWindowManager, filenames in MwGui now comply with naming conventions --- apps/openmw/mwgui/alchemywindow.cpp | 17 +- apps/openmw/mwgui/alchemywindow.hpp | 4 +- apps/openmw/mwgui/birth.cpp | 9 +- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 4 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.cpp | 2 +- apps/openmw/mwgui/class.cpp | 93 ++-- apps/openmw/mwgui/class.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 46 +- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/dialoguehistory.cpp | 76 +++ apps/openmw/mwgui/dialoguehistory.hpp | 19 + apps/openmw/mwgui/enchantingdialog.cpp | 42 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 20 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 8 +- apps/openmw/mwgui/loadingscreen.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 446 +++++++++++++++++ apps/openmw/mwgui/mapwindow.hpp | 107 ++++ apps/openmw/mwgui/merchantrepair.cpp | 10 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 5 +- apps/openmw/mwgui/messagebox.hpp | 8 +- apps/openmw/mwgui/quickkeysmenu.cpp | 20 +- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/race.cpp | 26 +- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 11 +- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 4 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 14 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 14 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 21 +- apps/openmw/mwgui/spellcreationdialog.hpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 18 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 580 ++++++++++++++++++++++ apps/openmw/mwgui/statswindow.hpp | 83 ++++ apps/openmw/mwgui/textinput.cpp | 70 +++ apps/openmw/mwgui/textinput.hpp | 33 ++ apps/openmw/mwgui/tooltips.cpp | 29 +- apps/openmw/mwgui/tooltips.hpp | 6 +- apps/openmw/mwgui/tradewindow.cpp | 24 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 18 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 18 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 14 +- apps/openmw/mwgui/waitdialog.hpp | 2 +- apps/openmw/mwgui/widgets.cpp | 39 +- apps/openmw/mwgui/widgets.hpp | 8 - apps/openmw/mwgui/windowbase.cpp | 54 ++ apps/openmw/mwgui/windowbase.hpp | 47 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 8 +- apps/openmw/mwgui/windowpinnablebase.cpp | 28 ++ apps/openmw/mwgui/windowpinnablebase.hpp | 28 ++ 72 files changed, 1863 insertions(+), 328 deletions(-) create mode 100644 apps/openmw/mwgui/dialoguehistory.cpp create mode 100644 apps/openmw/mwgui/dialoguehistory.hpp create mode 100644 apps/openmw/mwgui/mapwindow.cpp create mode 100644 apps/openmw/mwgui/mapwindow.hpp create mode 100644 apps/openmw/mwgui/statswindow.cpp create mode 100644 apps/openmw/mwgui/statswindow.hpp create mode 100644 apps/openmw/mwgui/textinput.cpp create mode 100644 apps/openmw/mwgui/textinput.hpp create mode 100644 apps/openmw/mwgui/windowbase.cpp create mode 100644 apps/openmw/mwgui/windowbase.hpp create mode 100644 apps/openmw/mwgui/windowpinnablebase.cpp create mode 100644 apps/openmw/mwgui/windowpinnablebase.hpp diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index ca7f1b913a..1ae534797d 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -64,8 +64,8 @@ namespace MWGui { mAlchemy.clear(); - mWindowManager.removeGuiMode(GM_Alchemy); - mWindowManager.removeGuiMode(GM_Inventory); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); } void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) @@ -77,40 +77,40 @@ namespace MWGui if (result == MWMechanics::Alchemy::Result_NoName) { - mWindowManager.messageBox("#{sNotifyMessage37}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage37}"); return; } // check if mortar & pestle is available (always needed) if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle) { - mWindowManager.messageBox("#{sNotifyMessage45}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage45}"); return; } // make sure 2 or more ingredients were selected if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients) { - mWindowManager.messageBox("#{sNotifyMessage6a}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage6a}"); return; } if (result == MWMechanics::Alchemy::Result_NoEffects) { - mWindowManager.messageBox("#{sNotifyMessage8}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); return; } if (result == MWMechanics::Alchemy::Result_Success) { - mWindowManager.messageBox("#{sPotionSuccess}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sPotionSuccess}"); MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f); } else if (result == MWMechanics::Alchemy::Result_RandomFailure) { // potion failed - mWindowManager.messageBox("#{sNotifyMessage8}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); } @@ -232,7 +232,6 @@ namespace MWGui MyGUI::IntCoord coord(0, 0, mEffectsBox->getWidth(), 24); Widgets::MWEffectListPtr effectsWidget = mEffectsBox->createWidget ("MW_StatName", coord, MyGUI::Align::Left | MyGUI::Align::Top); - effectsWidget->setWindowManager(&mWindowManager); Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list); effectsWidget->setEffectList(_list); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 5f84e73e9b..933975f0c8 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,7 +5,7 @@ #include "../mwmechanics/alchemy.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "container.hpp" #include "widgets.hpp" @@ -38,7 +38,7 @@ namespace MWGui virtual void onReferenceUnavailable() { ; } void update(); - + private: MWMechanics::Alchemy mAlchemy; diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 4b07dd698c..d899ab00b1 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -46,7 +46,7 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); updateBirths(); @@ -59,9 +59,9 @@ void BirthDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void BirthDialog::open() @@ -221,7 +221,7 @@ void BirthDialog::updateSpells() if (!categories[category].spells.empty()) { MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); - label->setCaption(mWindowManager.getGameSettingString(categories[category].label, "")); + label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); mSpellItems.push_back(label); coord.top += lineHeight; @@ -230,7 +230,6 @@ void BirthDialog::updateSpells() { const std::string &spellId = *it; spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); - spellWidget->setWindowManager(&mWindowManager); spellWidget->setSpellId(spellId); mSpellItems.push_back(spellWidget); diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index d3f82dace4..033501f22f 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_BIRTH_H #define MWGUI_BIRTH_H -#include "window_base.hpp" +#include "windowbase.hpp" /* This file contains the dialog for choosing a birth sign. diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 777751069b..d57953d07d 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -102,7 +102,7 @@ void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - mWindowManager.removeGuiMode(GM_Book); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) @@ -112,7 +112,7 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) MWWorld::ActionTake take(mBook); take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - mWindowManager.removeGuiMode(GM_Book); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index a509f131fe..c2a9dca893 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_BOOKWINDOW_H #define MWGUI_BOOKWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index bcf3c335d3..27de7cee98 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -1,6 +1,6 @@ #include "charactercreation.hpp" -#include "text_input.hpp" +#include "textinput.hpp" #include "race.hpp" #include "class.hpp" #include "birth.hpp" diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index a2f09096a1..8c352d5080 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -26,7 +26,7 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW // Centre dialog center(); - setText("ReflectT", mWindowManager.getGameSettingString("sMessageQuestionAnswer1", "")); + setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); getWidget(mClassImage, "ClassImage"); getWidget(mClassName, "ClassName"); @@ -37,7 +37,7 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); } @@ -77,16 +77,12 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); - mFavoriteAttribute[0]->setWindowManager(&mWindowManager); - mFavoriteAttribute[1]->setWindowManager(&mWindowManager); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - mMajorSkill[i]->setWindowManager(&mWindowManager); - mMinorSkill[i]->setWindowManager(&mWindowManager); } getWidget(mClassList, "ClassList"); @@ -115,9 +111,9 @@ void PickClassDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void PickClassDialog::open() @@ -224,7 +220,7 @@ void PickClassDialog::updateStats() "sSpecializationMagic", "sSpecializationStealth" }; - std::string specName = mWindowManager.getGameSettingString(specIds[specialization], specIds[specialization]); + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); mSpecializationName->setCaption(specName); ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); @@ -365,10 +361,10 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) { setText(""); ButtonList buttons; - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu1", "")); - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu2", "")); - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu3", "")); - buttons.push_back(mWindowManager.getGameSettingString("sBack", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); setButtons(buttons); } @@ -384,20 +380,18 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("SpecializationT", mWindowManager.getGameSettingString("sChooseClassMenu1", "Specialization")); + setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); getWidget(mSpecializationName, "SpecializationName"); mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); - setText("FavoriteAttributesT", mWindowManager.getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); + setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); - mFavoriteAttribute0->setWindowManager(&mWindowManager); - mFavoriteAttribute1->setWindowManager(&mWindowManager); mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - setText("MajorSkillT", mWindowManager.getGameSettingString("sSkillClassMajor", "")); - setText("MinorSkillT", mWindowManager.getGameSettingString("sSkillClassMinor", "")); + setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); + setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; @@ -410,11 +404,10 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) std::vector::const_iterator end = mSkills.end(); for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) { - (*it)->setWindowManager(&mWindowManager); (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); } - setText("LabelT", mWindowManager.getGameSettingString("sName", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); getWidget(mEditName, "EditName"); // Make sure the edit box has focus @@ -522,32 +515,32 @@ void CreateClassDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } // widget controls void CreateClassDialog::onDialogCancel() { - mWindowManager.removeDialog(mSpecDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); mSpecDialog = 0; - mWindowManager.removeDialog(mAttribDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); mAttribDialog = 0; - mWindowManager.removeDialog(mSkillDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); mSkillDialog = 0; - mWindowManager.removeDialog(mDescDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); mDescDialog = 0; } void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) { delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(mWindowManager); + mSpecDialog = new SelectSpecializationDialog(*MWBase::Environment::get().getWindowManager()); mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); mSpecDialog->setVisible(true); @@ -558,7 +551,7 @@ void CreateClassDialog::onSpecializationSelected() mSpecializationId = mSpecDialog->getSpecializationId(); setSpecialization(mSpecializationId); - mWindowManager.removeDialog(mSpecDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); mSpecDialog = 0; } @@ -570,7 +563,7 @@ void CreateClassDialog::setSpecialization(int id) "sSpecializationMagic", "sSpecializationStealth" }; - std::string specName = mWindowManager.getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); mSpecializationName->setCaption(specName); ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); } @@ -578,7 +571,7 @@ void CreateClassDialog::setSpecialization(int id) void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(mWindowManager); + mAttribDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager()); mAffectedAttribute = _sender; mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); @@ -599,7 +592,7 @@ void CreateClassDialog::onAttributeSelected() mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); } mAffectedAttribute->setAttributeId(id); - mWindowManager.removeDialog(mAttribDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); mAttribDialog = 0; update(); @@ -608,7 +601,7 @@ void CreateClassDialog::onAttributeSelected() void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(mWindowManager); + mSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager()); mAffectedSkill = _sender; mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); @@ -633,14 +626,14 @@ void CreateClassDialog::onSkillSelected() } mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); - mWindowManager.removeDialog(mSkillDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); mSkillDialog = 0; update(); } void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) { - mDescDialog = new DescriptionDialog(mWindowManager); + mDescDialog = new DescriptionDialog(*MWBase::Environment::get().getWindowManager()); mDescDialog->setTextInput(mDescription); mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); mDescDialog->setVisible(true); @@ -649,7 +642,7 @@ void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) { mDescription = mDescDialog->getTextInput(); - mWindowManager.removeDialog(mDescDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); mDescDialog = 0; } @@ -673,14 +666,14 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sSpecializationMenu1", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); getWidget(mSpecialization0, "Specialization0"); getWidget(mSpecialization1, "Specialization1"); getWidget(mSpecialization2, "Specialization2"); - std::string combat = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); - std::string magic = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); - std::string stealth = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); + std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); + std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); mSpecialization0->setCaption(combat); mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); @@ -696,7 +689,7 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); } @@ -733,7 +726,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sAttributesMenu1", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); for (int i = 0; i < 8; ++i) { @@ -741,7 +734,6 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan char theIndex = '0'+i; getWidget(attribute, std::string("Attribute").append(1, theIndex)); - attribute->setWindowManager(&parWindowManager); attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); @@ -749,7 +741,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); } @@ -780,10 +772,10 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sSkillsMenu1", "")); - setText("CombatLabelT", mWindowManager.getGameSettingString("sSpecializationCombat", "")); - setText("MagicLabelT", mWindowManager.getGameSettingString("sSpecializationMagic", "")); - setText("StealthLabelT", mWindowManager.getGameSettingString("sSpecializationStealth", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); + setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); + setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); + setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); for(int i = 0; i < 9; i++) { @@ -833,7 +825,6 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) { for (int i = 0; i < 9; ++i) { - mSkills[spec][i].widget->setWindowManager(&mWindowManager); mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); @@ -842,7 +833,7 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); } @@ -876,7 +867,7 @@ DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); - okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 8c60331d87..11da1a7913 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -3,7 +3,7 @@ #include "widgets.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" /* This file contains the dialogs for choosing a class. diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 45941f2ad0..a925cad550 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_CONFIRMATIONDIALOG_H #define MWGUI_CONFIRMATIONDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 7e6a0b0885..f7846e70ec 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -751,7 +751,7 @@ void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) /// \todo I don't think this is the correct flag to check if (MWWorld::Class::get(mPtr).isEssential(mPtr)) - mWindowManager.messageBox("#{sDisposeCorpseFail}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); else MWBase::Environment::get().getWorld()->deleteObject(mPtr); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 03bd519f7d..7a3e804e5d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -3,7 +3,7 @@ #include "../mwworld/esmstore.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "../mwclass/container.hpp" diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 80da6eea01..d5155839d8 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_COUNTDIALOG_H #define MWGUI_COUNTDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b3aa27617c..0939da1b17 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -18,7 +18,7 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" -#include "dialogue_history.hpp" +#include "dialoguehistory.hpp" #include "widgets.hpp" #include "list.hpp" #include "tradewindow.hpp" @@ -89,17 +89,17 @@ void PersuasionDialog::onPersuade(MyGUI::Widget *sender) else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; else if (sender == mBribe10Button) { - mWindowManager.getTradeWindow()->addOrRemoveGold(-10); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); type = MWBase::MechanicsManager::PT_Bribe10; } else if (sender == mBribe100Button) { - mWindowManager.getTradeWindow()->addOrRemoveGold(-100); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); type = MWBase::MechanicsManager::PT_Bribe100; } else /*if (sender == mBribe1000Button)*/ { - mWindowManager.getTradeWindow()->addOrRemoveGold(-1000); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); type = MWBase::MechanicsManager::PT_Bribe1000; } @@ -113,7 +113,7 @@ void PersuasionDialog::open() WindowModal::open(); center(); - int playerGold = mWindowManager.getInventoryWindow()->getPlayerGold(); + int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); mBribe10Button->setEnabled (playerGold >= 10); mBribe100Button->setEnabled (playerGold >= 100); @@ -251,45 +251,45 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) } else if (topic == gmst.find("sCompanionShare")->getString()) { - mWindowManager.pushGuiMode(GM_Companion); - mWindowManager.showCompanionWindow(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); + MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); } else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) { - mWindowManager.pushGuiMode(GM_Barter); - mWindowManager.getTradeWindow()->startTrade(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); } else if (topic == gmst.find("sSpells")->getString()) { - mWindowManager.pushGuiMode(GM_SpellBuying); - mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); } else if (topic == gmst.find("sTravel")->getString()) { - mWindowManager.pushGuiMode(GM_Travel); - mWindowManager.getTravelWindow()->startTravel(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); } else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) { - mWindowManager.pushGuiMode(GM_SpellCreation); - mWindowManager.startSpellMaking (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); } else if (topic == gmst.find("sEnchanting")->getString()) { - mWindowManager.pushGuiMode(GM_Enchanting); - mWindowManager.startEnchanting (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); + MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); } else if (topic == gmst.find("sServiceTrainingTitle")->getString()) { - mWindowManager.pushGuiMode(GM_Training); - mWindowManager.startTraining (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->startTraining (mPtr); } else if (topic == gmst.find("sRepair")->getString()) { - mWindowManager.pushGuiMode(GM_MerchantRepair); - mWindowManager.startRepair (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->startRepair (mPtr); } } } @@ -456,7 +456,7 @@ std::string DialogueWindow::parseText(const std::string& text) } else { - if( !mWindowManager.getTranslationDataStorage().hasTranslation() ) + if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) { @@ -528,7 +528,7 @@ void DialogueWindow::goodbye() void DialogueWindow::onReferenceUnavailable() { - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void DialogueWindow::onFrame() diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 187731fc77..e78856c951 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_DIALOGE_H #define MWGUI_DIALOGE_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include diff --git a/apps/openmw/mwgui/dialoguehistory.cpp b/apps/openmw/mwgui/dialoguehistory.cpp new file mode 100644 index 0000000000..a122a78916 --- /dev/null +++ b/apps/openmw/mwgui/dialoguehistory.cpp @@ -0,0 +1,76 @@ +#include "dialoguehistory.hpp" + +#include "../mwbase/windowmanager.hpp" + +#include "widgets.hpp" + +#include "../mwworld/esmstore.hpp" + +#include +#include + +#include +#include + +using namespace MWGui; +using namespace Widgets; + +MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) +{ + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::TextIterator iterator(getCaption()); + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if (pos < _pos) + continue; + else if (pos == _pos) + break; + } + return colour; +} + +MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) +{ + bool breakOnNext = false; + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::UString colour2 = colour; + MyGUI::TextIterator iterator(getCaption()); + MyGUI::TextIterator col_start = iterator; + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if(colour != colour2) + { + if(breakOnNext) + { + return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + } + col_start = iterator; + colour2 = colour; + } + if (pos < _pos) + continue; + else if (pos == _pos) + { + breakOnNext = true; + } + } + return ""; +} + +void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) +{ + MyGUI::UString head("\n#D8C09A"); + head.append(parText); + head.append("#B29154\n"); + addText(head); +} + +void DialogueHistory::addDialogText(const MyGUI::UString& parText) +{ + addText(parText); + addText("\n"); +} diff --git a/apps/openmw/mwgui/dialoguehistory.hpp b/apps/openmw/mwgui/dialoguehistory.hpp new file mode 100644 index 0000000000..c37504af77 --- /dev/null +++ b/apps/openmw/mwgui/dialoguehistory.hpp @@ -0,0 +1,19 @@ +#ifndef MWGUI_DIALOGE_HISTORY_H +#define MWGUI_DIALOGE_HISTORY_H +#include + +namespace MWGui +{ + class DialogueHistory : public MyGUI::EditBox + { + MYGUI_RTTI_DERIVED( DialogueHistory ) + public: + Widget* getClient() { return mClient; } + MyGUI::UString getColorAtPos(size_t _pos); + MyGUI::UString getColorTextAt(size_t _pos); + void addDialogHeading(const MyGUI::UString& parText); + void addDialogText(const MyGUI::UString& parText); + }; +} +#endif + diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 276e7a9047..02d847d1a8 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -69,19 +69,19 @@ namespace MWGui switch(mEnchanting.getEnchantType()) { case 0: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastOnce","Cast Once")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); mAddEffectDialog.constantEffect=false; break; case 1: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenStrikes", "When Strikes")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); mAddEffectDialog.constantEffect=false; break; case 2: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenUsed", "When Used")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); mAddEffectDialog.constantEffect=false; break; case 3: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastConstant", "Cast Constant")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); mAddEffectDialog.constantEffect=true; break; } @@ -126,20 +126,20 @@ namespace MWGui void EnchantingDialog::onReferenceUnavailable () { - mWindowManager.removeGuiMode (GM_Dialogue); - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } void EnchantingDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}", - ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, mWindowManager); + ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); @@ -190,7 +190,7 @@ namespace MWGui if(mEnchanting.getGemCharge()==0) { - mWindowManager.messageBox ("#{sNotifyMessage32}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage32}"); return; } @@ -227,14 +227,14 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}", - ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, mWindowManager); + ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mItemSelectionDialog->drawItems (); - //mWindowManager.messageBox("#{sInventorySelectNoSoul}"); + //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); } void EnchantingDialog::notifyEffectsChanged () @@ -254,50 +254,50 @@ namespace MWGui { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}"); return; } if (mName->getCaption ().empty()) { - mWindowManager.messageBox ("#{sNotifyMessage10}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; } if (mEnchanting.soulEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage52}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage52}"); return; } if (mEnchanting.itemEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage11}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage11}"); return; } if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue()) { - mWindowManager.messageBox ("#{sNotifyMessage29}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}"); return; } mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - if (mEnchanting.getEnchantPrice() > mWindowManager.getInventoryWindow()->getPlayerGold()) + if (mEnchanting.getEnchantPrice() > MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; } int result = mEnchanting.create(); if(result==1) - mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu12}"); else - mWindowManager.messageBox ("#{sNotifyMessage34}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage34}"); - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index a7861c422d..822199ac67 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_ENCHANTINGDIALOG_H #define MWGUI_ENCHANTINGDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "spellcreationdialog.hpp" diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index aab9e62a4f..c65566ce3e 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -1,4 +1,4 @@ -#include "map_window.hpp" +#include "mapwindow.hpp" #include diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 001f42bd11..393f03a541 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -130,7 +130,7 @@ namespace MWGui void InventoryWindow::onPinToggled() { - mWindowManager.setWeaponVisibility(!mPinned); + MWBase::Environment::get().getWindowManager()->setWeaponVisibility(!mPinned); } void InventoryWindow::onAvatarClicked(MyGUI::Widget* _sender) @@ -162,13 +162,13 @@ namespace MWGui // the "Take" button should not be visible. // NOTE: the take button is "reset" when the window opens, so we can safely do the following // without screwing up future book windows - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - mWindowManager.setDragDrop(false); + MWBase::Environment::get().getWindowManager()->setDragDrop(false); drawItems(); @@ -224,11 +224,11 @@ namespace MWGui { invStore.equip(slot, invStore.end()); std::string script = MWWorld::Class::get(*it).getScript(*it); - + // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared if(script != "") (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 0); - + return; } } @@ -285,16 +285,16 @@ namespace MWGui void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory - if (mWindowManager.getSpellWindow()) - mWindowManager.getSpellWindow()->updateSpells(); + if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) + MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); // update selected weapon icon MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if (weaponSlot == invStore.end()) - mWindowManager.unsetSelectedWeapon(); + MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon(); else - mWindowManager.setSelectedWeapon(*weaponSlot); /// \todo track weapon durability + MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*weaponSlot); /// \todo track weapon durability mPreviewDirty = true; diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fceb7ecef1..61ee17ef93 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -4,7 +4,7 @@ #include "../mwrender/characterpreview.hpp" #include "container.hpp" -#include "window_pinnable_base.hpp" +#include "windowpinnablebase.hpp" #include "widgets.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cd1ff7ebbd..73a2dca2ec 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -6,7 +6,7 @@ #include #include -#include "window_base.hpp" +#include "windowbase.hpp" #include "imagebutton.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 67620d49da..dcecdccc1b 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -183,7 +183,7 @@ namespace MWGui creatureStats.setLevel (creatureStats.getLevel()+1); pcStats.levelUp (); - mWindowManager.removeGuiMode (GM_Levelup); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Levelup); } } diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index 3c8b74800b..a54948e2a0 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_LEVELUPDIALOG_H #define MWGUI_LEVELUPDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 86f196d9f5..3066705124 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -195,12 +195,12 @@ namespace MWGui { changeWallpaper(); - mWindowManager.pushGuiMode(GM_LoadingWallpaper); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_LoadingWallpaper); } else { mBackgroundImage->setImageTexture(""); - mWindowManager.pushGuiMode(GM_Loading); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Loading); } } @@ -211,8 +211,8 @@ namespace MWGui mLoadingOn = false; mFirstLoad = false; - mWindowManager.removeGuiMode(GM_Loading); - mWindowManager.removeGuiMode(GM_LoadingWallpaper); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_LoadingWallpaper); } void LoadingScreen::changeWallpaper () diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 176fc0f5d5..cb33975ae3 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -4,7 +4,7 @@ #include #include -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp new file mode 100644 index 0000000000..029974d2b3 --- /dev/null +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -0,0 +1,446 @@ +#include "mapwindow.hpp" + +#include + +#include +#include +#include + +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" + +#include "../mwrender/globalmap.hpp" + +#include "widgets.hpp" + +using namespace MWGui; + +LocalMapBase::LocalMapBase() + : mCurX(0) + , mCurY(0) + , mInterior(false) + , mFogOfWar(true) + , mLocalMap(NULL) + , mMapDragAndDrop(false) + , mPrefix() + , mChanged(true) + , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) + , mCompass(NULL) +{ +} + +void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) +{ + mLocalMap = widget; + mLayout = layout; + mMapDragAndDrop = mapDragAndDrop; + mCompass = compass; + + // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each + const int widgetSize = 512; + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", + MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); + + MyGUI::ImageBox* fog = map->createWidget("ImageBox", + MyGUI::IntCoord(0, 0, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); + + if (!mMapDragAndDrop) + { + map->setNeedMouseFocus(false); + fog->setNeedMouseFocus(false); + } + + mMapWidgets.push_back(map); + mFogWidgets.push_back(fog); + } + } +} + +void LocalMapBase::setCellPrefix(const std::string& prefix) +{ + mPrefix = prefix; + mChanged = true; +} + +void LocalMapBase::toggleFogOfWar() +{ + mFogOfWar = !mFogOfWar; + applyFogOfWar(); +} + +void LocalMapBase::applyFogOfWar() +{ + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" + + boost::lexical_cast(mCurY + (-1*(my-1))); + MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; + fog->setImageTexture(mFogOfWar ? + ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" + : "black.png" ) + : ""); + } + } + notifyMapChanged (); +} + +void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) +{ + applyFogOfWar (); +} + +void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) +{ + applyFogOfWar (); +} + +void LocalMapBase::setActiveCell(const int x, const int y, bool interior) +{ + if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell + + // clear all previous markers + for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) + { + if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + { + MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); + } + } + + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + // map + std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + + boost::lexical_cast(y + (-1*(my-1))); + + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; + + if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) + box->setImageTexture(image); + else + box->setImageTexture("black.png"); + + + // door markers + + // interior map only consists of one cell, so handle the markers only once + if (interior && (mx != 2 || my != 2)) + continue; + + MWWorld::CellStore* cell; + if (interior) + cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); + else + cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); + + std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); + + for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + { + MWBase::World::DoorMarker marker = *it; + + // convert world coordinates to normalized cell coordinates + MyGUI::IntCoord widgetCoord; + float nX,nY; + int cellDx, cellDy; + if (!interior) + { + const int cellSize = 8192; + + nX = (marker.x - cellSize * (x+mx-1)) / cellSize; + nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + } + else + { + Ogre::Vector2 position (marker.x, marker.y); + MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + } + + static int counter = 0; + ++counter; + MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); + markerWidget->setUserString("IsMarker", "true"); + markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); + markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); + + MarkerPosition markerPos; + markerPos.interior = interior; + markerPos.cellX = interior ? cellDx : x + mx - 1; + markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); + markerPos.nX = nX; + markerPos.nY = nY; + + markerWidget->setUserData(markerPos); + } + + + } + } + mInterior = interior; + mCurX = x; + mCurY = y; + mChanged = false; + + // fog of war + applyFogOfWar(); + + // set the compass texture again, because MyGUI determines sorting of ImageBox widgets + // based on the last setImageTexture call + std::string tex = "textures\\compass.dds"; + mCompass->setImageTexture(""); + mCompass->setImageTexture(tex); +} + + +void LocalMapBase::setPlayerPos(const float x, const float y) +{ + if (x == mLastPositionX && y == mLastPositionY) + return; + + notifyPlayerUpdate (); + + MyGUI::IntSize size = mLocalMap->getCanvasSize(); + MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); + MyGUI::IntCoord viewsize = mLocalMap->getCoord(); + MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + mLocalMap->setViewOffset(pos); + + mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); + mLastPositionX = x; + mLastPositionY = y; +} + +void LocalMapBase::setPlayerDir(const float x, const float y) +{ + if (x == mLastDirectionX && y == mLastDirectionY) + return; + + notifyPlayerUpdate (); + + MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(x,y); + rotatingSubskin->setAngle(angle); + + mLastDirectionX = x; + mLastDirectionY = y; +} + +// ------------------------------------------------------------------------------------------ + +MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) + , mGlobal(false) +{ + setCoord(500,0,320,300); + + mGlobalMapRender = new MWRender::GlobalMap(cacheDir); + mGlobalMapRender->render(); + + getWidget(mLocalMap, "LocalMap"); + getWidget(mGlobalMap, "GlobalMap"); + getWidget(mGlobalMapImage, "GlobalMapImage"); + getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); + getWidget(mPlayerArrowLocal, "CompassLocal"); + getWidget(mPlayerArrowGlobal, "CompassGlobal"); + + mGlobalMapImage->setImageTexture("GlobalMap.png"); + mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + + mGlobalMap->setVisible (false); + + getWidget(mButton, "WorldButton"); + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing("#{sWorld}"); + + getWidget(mEventBoxGlobal, "EventBoxGlobal"); + mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + getWidget(mEventBoxLocal, "EventBoxLocal"); + mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); +} + +MapWindow::~MapWindow() +{ + delete mGlobalMapRender; +} + +void MapWindow::setCellName(const std::string& cellName) +{ + setTitle("#{sCell=" + cellName + "}"); +} + +void MapWindow::addVisitedLocation(const std::string& name, int x, int y) +{ + float worldX, worldY; + mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); + + MyGUI::IntCoord widgetCoord( + worldX * mGlobalMapRender->getWidth()+6, + worldY * mGlobalMapRender->getHeight()+6, + 12, 12); + + + static int _counter=0; + MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + ++_counter; + + markerWidget = mEventBoxGlobal->createWidget("", + widgetCoord, MyGUI::Align::Default); + markerWidget->setNeedMouseFocus (true); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); +} + +void MapWindow::cellExplored(int x, int y) +{ + mGlobalMapRender->exploreCell(x,y); +} + +void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) +{ + if (_id!=MyGUI::MouseButton::Left) return; + mLastDragPos = MyGUI::IntPoint(_left, _top); +} + +void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) +{ + if (_id!=MyGUI::MouseButton::Left) return; + + MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; + + if (!mGlobal) + mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + else + mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); + + + mLastDragPos = MyGUI::IntPoint(_left, _top); +} + +void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) +{ + mGlobal = !mGlobal; + mGlobalMap->setVisible(mGlobal); + mLocalMap->setVisible(!mGlobal); + + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + + if (mGlobal) + globalMapUpdatePlayer (); +} + +void MapWindow::onPinToggled() +{ + MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); +} + +void MapWindow::open() +{ + mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + + for (unsigned int i=0; igetChildCount (); ++i) + { + if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") + mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + } + + globalMapUpdatePlayer(); + + mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); +} + +void MapWindow::globalMapUpdatePlayer () +{ + Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); + Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); + + float worldX, worldY; + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); + worldX *= mGlobalMapRender->getWidth(); + worldY *= mGlobalMapRender->getHeight(); + + + // for interiors, we have no choice other than using the last position & direction. + /// \todo save this last position in the savegame? + if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + { + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + + MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(dir.x, dir.y); + rotatingSubskin->setAngle(angle); + + // set the view offset so that player is in the center + MyGUI::IntSize viewsize = mGlobalMap->getSize(); + MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); + mGlobalMap->setViewOffset(viewoffs); + } +} + +void MapWindow::notifyPlayerUpdate () +{ + globalMapUpdatePlayer (); +} + +void MapWindow::notifyMapChanged () +{ + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); +} diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp new file mode 100644 index 0000000000..329854e182 --- /dev/null +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -0,0 +1,107 @@ +#ifndef MWGUI_MAPWINDOW_H +#define MWGUI_MAPWINDOW_H + +#include "windowpinnablebase.hpp" + +namespace MWRender +{ + class GlobalMap; +} + +namespace MWGui +{ + class LocalMapBase + { + public: + LocalMapBase(); + void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false); + + void setCellPrefix(const std::string& prefix); + void setActiveCell(const int x, const int y, bool interior=false); + void setPlayerDir(const float x, const float y); + void setPlayerPos(const float x, const float y); + + void toggleFogOfWar(); + + struct MarkerPosition + { + bool interior; + int cellX; + int cellY; + float nX; + float nY; + }; + + protected: + int mCurX, mCurY; + bool mInterior; + MyGUI::ScrollView* mLocalMap; + MyGUI::ImageBox* mCompass; + std::string mPrefix; + bool mChanged; + bool mFogOfWar; + + std::vector mMapWidgets; + std::vector mFogWidgets; + + void applyFogOfWar(); + + void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); + void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); + + virtual void notifyPlayerUpdate() {} + virtual void notifyMapChanged() {} + + OEngine::GUI::Layout* mLayout; + + bool mMapDragAndDrop; + + float mLastPositionX; + float mLastPositionY; + float mLastDirectionX; + float mLastDirectionY; + }; + + class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase + { + public: + MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); + virtual ~MapWindow(); + + void setCellName(const std::string& cellName); + + void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map + void cellExplored(int x, int y); + + virtual void open(); + + private: + void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onWorldButtonClicked(MyGUI::Widget* _sender); + + void globalMapUpdatePlayer(); + + MyGUI::ScrollView* mGlobalMap; + MyGUI::ImageBox* mGlobalMapImage; + MyGUI::ImageBox* mGlobalMapOverlay; + MyGUI::ImageBox* mPlayerArrowLocal; + MyGUI::ImageBox* mPlayerArrowGlobal; + MyGUI::Button* mButton; + MyGUI::IntPoint mLastDragPos; + bool mGlobal; + + MyGUI::Button* mEventBoxGlobal; + MyGUI::Button* mEventBoxLocal; + + MWRender::GlobalMap* mGlobalMapRender; + + protected: + virtual void onPinToggled(); + + virtual void notifyPlayerUpdate(); + virtual void notifyMapChanged(); + + }; +} +#endif diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 1c9056748b..f24d2d4177 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -72,7 +72,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) MyGUI::Button* button = mList->createWidget( - (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + (price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, currentY, 0, @@ -82,7 +82,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; - button->setEnabled(price<=mWindowManager.getInventoryWindow()->getPlayerGold()); + button->setEnabled(price<=MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()); button->setUserString("Price", boost::lexical_cast(price)); button->setUserData(*iter); button->setCaptionWithReplacing(name); @@ -95,7 +95,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY))); mGoldLabel->setCaptionWithReplacing("#{sGold}: " - + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); } void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) @@ -120,14 +120,14 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); int price = boost::lexical_cast(sender->getUserString("Price")); - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); startRepair(mActor); } void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 4b7e2b8fbd..2cd6c486a9 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWGUI_MERCHANTREPAIR_H #define OPENMW_MWGUI_MERCHANTREPAIR_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 46663b67a5..58bbc3c3ab 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -7,9 +7,8 @@ using namespace MWGui; -MessageBoxManager::MessageBoxManager (MWBase::WindowManager *windowManager) +MessageBoxManager::MessageBoxManager (MWBase::WindowManager* windowManager) { - mWindowManager = windowManager; // defines mMessageBoxSpeed = 0.1; mInterMessageBoxe = NULL; @@ -371,7 +370,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan void InteractiveMessageBox::enterPressed() { - + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 859e1806a7..c64953b665 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -3,7 +3,7 @@ #include -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwbase/windowmanager.hpp" @@ -40,7 +40,7 @@ namespace MWGui void removeMessageBox (float time, MessageBox *msgbox); bool removeMessageBox (MessageBox *msgbox); void setMessageBoxSpeed (int speed); - + void enterPressed(); int readPressedButton (); @@ -51,8 +51,6 @@ namespace MWGui void onButtonPressed(int button) { eventButtonPressed(button); eventButtonPressed.clear(); } - MWBase::WindowManager *mWindowManager; - private: std::vector mMessageBoxes; InteractiveMessageBox* mInterMessageBoxe; @@ -92,7 +90,7 @@ namespace MWGui private: void buttonActivated (MyGUI::Widget* _widget); - + MessageBoxManager& mMessageBoxManager; MyGUI::EditBox* mMessageWidget; MyGUI::Widget* mButtonsWidget; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 2e4bf9100b..82835a8058 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -109,14 +109,14 @@ namespace MWGui { // open assign dialog if (!mAssignDialog) - mAssignDialog = new QuickKeysMenuAssign(mWindowManager, this); + mAssignDialog = new QuickKeysMenuAssign(*MWBase::Environment::get().getWindowManager(), this); mAssignDialog->setVisible (true); } } void QuickKeysMenu::onOkButtonClicked (MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_QuickKeysMenu); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_QuickKeysMenu); } @@ -124,7 +124,7 @@ namespace MWGui { if (!mItemSelectionDialog ) { - mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, mWindowManager); + mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItem); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } @@ -139,7 +139,7 @@ namespace MWGui { if (!mMagicSelectionDialog ) { - mMagicSelectionDialog = new MagicSelectionDialog(mWindowManager, this); + mMagicSelectionDialog = new MagicSelectionDialog(*MWBase::Environment::get().getWindowManager(), this); } mMagicSelectionDialog->setVisible(true); @@ -281,7 +281,7 @@ namespace MWGui std::string spellId = button->getChildAt(0)->getUserString("Spell"); spells.setSelectedSpell(spellId); store.setSelectedEnchantItem(store.end()); - mWindowManager.setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); } else if (type == Type_Item) { @@ -303,11 +303,11 @@ namespace MWGui // the "Take" button should not be visible. // NOTE: the take button is "reset" when the window opens, so we can safely do the following // without screwing up future book windows - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } else if (type == Type_MagicItem) { @@ -341,12 +341,12 @@ namespace MWGui action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item); + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 345ffa0c87..d5b6e6cd85 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -4,7 +4,7 @@ #include "../mwworld/ptr.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index be693eb2ba..167ad573a0 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -74,7 +74,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("AppearanceT", mWindowManager.getGameSettingString("sRaceMenu1", "Appearance")); + setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); getWidget(mPreviewImage, "PreviewImage"); getWidget(mHeadRotate, "HeadRotate"); @@ -86,34 +86,34 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) // Set up next/previous buttons MyGUI::Button *prevButton, *nextButton; - setText("GenderChoiceT", mWindowManager.getGameSettingString("sRaceMenu2", "Change Sex")); + setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); getWidget(prevButton, "PrevGenderButton"); getWidget(nextButton, "NextGenderButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); - setText("FaceChoiceT", mWindowManager.getGameSettingString("sRaceMenu3", "Change Face")); + setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); getWidget(prevButton, "PrevFaceButton"); getWidget(nextButton, "NextFaceButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); - setText("HairChoiceT", mWindowManager.getGameSettingString("sRaceMenu4", "Change Hair")); + setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); getWidget(prevButton, "PrevHairButton"); getWidget(nextButton, "NextHairButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu5", "Race")); + setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); getWidget(mRaceList, "RaceList"); mRaceList->setScrollVisible(true); mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - setText("SkillsT", mWindowManager.getGameSettingString("sBonusSkillTitle", "Skill Bonus")); + setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); getWidget(mSkillList, "SkillList"); - setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials")); + setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); getWidget(mSpellPowerList, "SpellPowerList"); MyGUI::Button* backButton; @@ -122,7 +122,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); updateRaces(); @@ -136,9 +136,9 @@ void RaceDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void RaceDialog::open() @@ -156,7 +156,7 @@ void RaceDialog::open() const ESM::NPC proto = mPreview->getPrototype(); setRaceId(proto.mRace); recountParts(); - + std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); mFaceIndex = boost::lexical_cast(index) - 1; @@ -361,7 +361,7 @@ void RaceDialog::updateRaces() const MWWorld::Store &races = MWBase::Environment::get().getWorld()->getStore().get(); - + int index = 0; MWWorld::Store::iterator it = races.begin(); for (; it != races.end(); ++it) @@ -403,7 +403,6 @@ void RaceDialog::updateSkills() skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, std::string("Skill") + boost::lexical_cast(i)); - skillWidget->setWindowManager(&mWindowManager); skillWidget->setSkillNumber(skillId); skillWidget->setSkillValue(MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); ToolTips::createSkillToolTip(skillWidget, skillId); @@ -439,7 +438,6 @@ void RaceDialog::updateSpellPowers() { const std::string &spellpower = *it; spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); - spellPowerWidget->setWindowManager(&mWindowManager); spellPowerWidget->setSpellId(spellpower); spellPowerWidget->setUserString("ToolTipType", "Spell"); spellPowerWidget->setUserString("Spell", spellpower); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 0ca440ad53..4a4acd0112 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -8,7 +8,7 @@ #include "../mwrender/characterpreview.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index f53ddc4305..43c262ad85 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -133,7 +133,7 @@ void Repair::updateRepairView() void Repair::onCancel(MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_Repair); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } void Repair::onRepairItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index c14b1955bd..824e0b6d2a 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWGUI_REPAIR_H #define OPENMW_MWGUI_REPAIR_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" #include "../mwmechanics/repair.hpp" diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 50508cc5f0..74b1893456 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -53,15 +53,15 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) // Setup dynamic stats getWidget(mHealth, "Health"); - mHealth->setTitle(mWindowManager.getGameSettingString("sHealth", "")); + mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); mHealth->setValue(45, 45); getWidget(mMagicka, "Magicka"); - mMagicka->setTitle(mWindowManager.getGameSettingString("sMagic", "")); + mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); mMagicka->setValue(50, 50); getWidget(mFatigue, "Fatigue"); - mFatigue->setTitle(mWindowManager.getGameSettingString("sFatigue", "")); + mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); mFatigue->setValue(160, 160); // Setup attributes @@ -71,7 +71,6 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) { getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); - attribute->setWindowManager(&mWindowManager); attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); attribute->setAttributeValue(MWAttribute::AttributeValue(0, 0)); } @@ -277,7 +276,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId addSeparator(coord1, coord2); } - addGroup(mWindowManager.getGameSettingString(titleId, titleDefault), coord1, coord2); + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); SkillList::const_iterator end = skills.end(); for (SkillList::const_iterator it = skills.begin(); it != end; ++it) @@ -296,7 +295,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId state = "increased"; else if (modified < base) state = "decreased"; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); for (int i=0; i<2; ++i) { diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 4f41ec42d6..9775a52de4 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_REVIEW_H #define MWGUI_REVIEW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwmechanics/stat.hpp" #include "widgets.hpp" diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 3bd3a47439..22884bfe6d 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -66,7 +66,7 @@ void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - mWindowManager.removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) @@ -76,5 +76,5 @@ void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mScroll); take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - mWindowManager.removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 42b6395a9a..59b39cab38 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SCROLLWINDOW_H #define MWGUI_SCROLLWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "imagebutton.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 58754472dd..e21d4f5894 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -274,7 +274,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_Settings); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -282,7 +282,7 @@ namespace MWGui if (index == MyGUI::ITEM_NONE) return; - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sNotifyMessage67}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); @@ -329,8 +329,8 @@ namespace MWGui void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) { - std::string on = mWindowManager.getGameSettingString("sOn", "On"); - std::string off = mWindowManager.getGameSettingString("sOff", "On"); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); + std::string off = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOff", "On"); bool newState; if (_sender->castType()->getCaption() == on) { @@ -437,8 +437,8 @@ namespace MWGui void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) { - std::string on = mWindowManager.getGameSettingString("sOn", "On"); - std::string off = mWindowManager.getGameSettingString("sOff", "On"); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); + std::string off = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOff", "On"); std::string val = static_cast(_sender)->getCaption(); if (val == off) @@ -610,7 +610,7 @@ namespace MWGui void SettingsWindow::onResetDefaultBindings(MyGUI::Widget* _sender) { - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sNotifyMessage66}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindingsAccept); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index fc1ec9e365..292c1233de 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SETTINGS_H #define MWGUI_SETTINGS_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index d39ad6a5ae..9aa8074a24 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -48,7 +48,7 @@ namespace MWGui MyGUI::Button* toAdd = mSpellsView->createWidget( - (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + (price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, @@ -120,13 +120,13 @@ namespace MWGui { int price = *_sender->getUserData(); - if (mWindowManager.getInventoryWindow()->getPlayerGold()>=price) + if (MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()>=price) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); spells.add (mSpellsWidgetMap.find(_sender)->second); - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); startSpellBuying(mPtr); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); @@ -135,12 +135,12 @@ namespace MWGui void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); } void SpellBuyingWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, @@ -150,8 +150,8 @@ namespace MWGui void SpellBuyingWindow::onReferenceUnavailable() { // remove both Spells and Dialogue (since you always trade with the NPC/creature that you have previously talked to) - mWindowManager.removeGuiMode(GM_SpellBuying); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void SpellBuyingWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index f9cda35df0..1418a9db52 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SpellBuyingWINDOW_H #define MWGUI_SpellBuyingWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" namespace MyGUI diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 592063a761..6fef91457f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -303,38 +303,38 @@ namespace MWGui void SpellCreationDialog::onCancelButtonClicked (MyGUI::Widget* sender) { - mWindowManager.removeGuiMode (MWGui::GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); } void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender) { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}"); return; } if (mNameEdit->getCaption () == "") { - mWindowManager.messageBox ("#{sNotifyMessage10}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; } if (mMagickaCost->getCaption() == "0") { - mWindowManager.messageBox ("#{sEnchantmentMenu8}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu8}"); return; } - if (boost::lexical_cast(mPriceLabel->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) + if (boost::lexical_cast(mPriceLabel->getCaption()) > MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; } mSpell.mName = mNameEdit->getCaption(); - mWindowManager.getTradeWindow()->addOrRemoveGold(-boost::lexical_cast(mPriceLabel->getCaption())); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-boost::lexical_cast(mPriceLabel->getCaption())); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); @@ -347,7 +347,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); - mWindowManager.removeGuiMode (GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } void SpellCreationDialog::open() @@ -357,8 +357,8 @@ namespace MWGui void SpellCreationDialog::onReferenceUnavailable () { - mWindowManager.removeGuiMode (GM_Dialogue); - mWindowManager.removeGuiMode (GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } void SpellCreationDialog::notifyEffectsChanged () @@ -601,7 +601,6 @@ namespace MWGui Widgets::MWSpellEffectPtr effect = button->createWidget("MW_EffectImage", MyGUI::IntCoord(0,0,0,24), MyGUI::Align::Default); effect->setNeedMouseFocus (false); - effect->setWindowManager (MWBase::Environment::get().getWindowManager ()); effect->setSpellEffect (params); effect->setSize(effect->getRequestedWidth (), 24); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 8f1c071804..facbdf5304 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SPELLCREATION_H #define MWGUI_SPELLCREATION_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "list.hpp" #include "widgets.hpp" diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 021a849a08..257fab89d4 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -71,7 +71,7 @@ namespace MWGui void SpellWindow::onPinToggled() { - mWindowManager.setSpellVisibility(!mPinned); + MWBase::Environment::get().getWindowManager()->setSpellVisibility(!mPinned); } void SpellWindow::open() @@ -140,7 +140,7 @@ namespace MWGui { store.setSelectedEnchantItem(store.end()); spells.setSelectedSpell(""); - mWindowManager.unsetSelectedSpell(); + MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); selectedItem = MWWorld::Ptr(); } } @@ -377,12 +377,12 @@ namespace MWGui action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item); + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); updateSpells(); } @@ -404,14 +404,14 @@ namespace MWGui if (spell->mData.mFlags & ESM::Spell::F_Always || spell->mData.mType == ESM::Spell::ST_Power) { - mWindowManager.messageBox("#{sDeleteSpellError}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); } else { // ask for confirmation mSpellToDelete = spellId; - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); - std::string question = mWindowManager.getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); question = boost::str(boost::format(question) % spell->mName); dialog->open(question); dialog->eventOkClicked.clear(); @@ -423,7 +423,7 @@ namespace MWGui { spells.setSelectedSpell(spellId); store.setSelectedEnchantItem(store.end()); - mWindowManager.setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); } updateSpells(); @@ -454,7 +454,7 @@ namespace MWGui if (spells.getSelectedSpell() == mSpellToDelete) { spells.setSelectedSpell(""); - mWindowManager.unsetSelectedSpell(); + MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); } spells.remove(mSpellToDelete); diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 1963d43463..b0994c5901 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SPELLWINDOW_H #define MWGUI_SPELLWINDOW_H -#include "window_pinnable_base.hpp" +#include "windowpinnablebase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp new file mode 100644 index 0000000000..0e0676c2fb --- /dev/null +++ b/apps/openmw/mwgui/statswindow.cpp @@ -0,0 +1,580 @@ +#include "statswindow.hpp" + +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "tooltips.hpp" + + +using namespace MWGui; +const int StatsWindow::sLineHeight = 18; + +StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) + : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) + , mSkillView(NULL) + , mClientHeight(0) + , mMajorSkills() + , mMinorSkills() + , mMiscSkills() + , mSkillValues() + , mSkillWidgetMap() + , mFactionWidgetMap() + , mFactions() + , mBirthSignId() + , mReputation(0) + , mBounty(0) + , mSkillWidgets() + , mChanged(true) +{ + setCoord(0,0,498, 342); + + const char *names[][2] = + { + { "Attrib1", "sAttributeStrength" }, + { "Attrib2", "sAttributeIntelligence" }, + { "Attrib3", "sAttributeWillpower" }, + { "Attrib4", "sAttributeAgility" }, + { "Attrib5", "sAttributeSpeed" }, + { "Attrib6", "sAttributeEndurance" }, + { "Attrib7", "sAttributePersonality" }, + { "Attrib8", "sAttributeLuck" }, + { 0, 0 } + }; + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for (int i=0; names[i][0]; ++i) + { + setText (names[i][0], store.get().find (names[i][1])->getString()); + } + + getWidget(mSkillView, "SkillView"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); + + for (int i = 0; i < ESM::Skill::Length; ++i) + { + mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); + } + + MyGUI::WindowPtr t = static_cast(mMainWidget); + t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); +} + +void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); +} + +void StatsWindow::onWindowResize(MyGUI::Window* window) +{ + mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); + mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); +} + +void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) +{ + MyGUI::ProgressPtr pt; + getWidget(pt, name); + pt->setProgressRange(max); + pt->setProgressPosition(val); + + std::stringstream out; + out << val << "/" << max; + setText(tname, out.str().c_str()); +} + +void StatsWindow::setPlayerName(const std::string& playerName) +{ + static_cast(mMainWidget)->setCaption(playerName); + adjustWindowCaption(); +} + +void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) +{ + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + if (ids[i]==id) + { + std::ostringstream valueString; + valueString << value.getModified(); + setText (id, valueString.str()); + + MyGUI::TextBox* box; + getWidget(box, id); + + if (value.getModified()>value.getBase()) + box->_setWidgetState("increased"); + else if (value.getModified()_setWidgetState("decreased"); + else + box->_setWidgetState("normal"); + + break; + } +} + +void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) +{ + static const char *ids[] = + { + "HBar", "MBar", "FBar", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) + { + std::string id (ids[i]); + setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); + + // health, magicka, fatigue tooltip + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + if (i==0) + { + getWidget(w, "Health"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + else if (i==1) + { + getWidget(w, "Magicka"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + else if (i==2) + { + getWidget(w, "Fatigue"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } + } + } +} + +void StatsWindow::setValue (const std::string& id, const std::string& value) +{ + if (id=="name") + setPlayerName (value); + else if (id=="race") + setText ("RaceText", value); + else if (id=="class") + setText ("ClassText", value); +} + +void StatsWindow::setValue (const std::string& id, int value) +{ + if (id=="level") + { + std::ostringstream text; + text << value; + setText("LevelText", text.str()); + } +} + +void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) +{ + mSkillValues[parSkill] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + + widget->setCaption(text); + widget->_setWidgetState(state); + } +} + +void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) +{ + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } + + updateSkillArea(); +} + +void StatsWindow::onFrame () +{ + if (!mMainWidget->getVisible()) + return; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + + // level progress + MyGUI::Widget* levelWidget; + for (int i=0; i<2; ++i) + { + getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); + levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); + levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + } + + setFactions(PCstats.getFactionRanks()); + setExpelled(PCstats.getExpelled ()); + + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + + setBirthSign(signId); + setReputation (PCstats.getReputation ()); + setBounty (PCstats.getBounty ()); + + if (mChanged) + updateSkillArea(); +} + +void StatsWindow::setFactions (const FactionList& factions) +{ + if (mFactions != factions) + { + mFactions = factions; + mChanged = true; + } +} + +void StatsWindow::setExpelled (const std::set& expelled) +{ + if (mExpelled != expelled) + { + mExpelled = expelled; + mChanged = true; + } +} + +void StatsWindow::setBirthSign (const std::string& signId) +{ + if (signId != mBirthSignId) + { + mBirthSignId = signId; + mChanged = true; + } +} + +void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", + MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); +} + +void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", + MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + groupWidget->setCaption(label); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; +} + +MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::TextBox *skillNameWidget, *skillValueWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; +} + +MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillNameWidget; +} + +void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + int progressPercent = (modified - float(static_cast(modified))) * 100; + + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Skill* skill = esmStore.get().find(skillId); + assert(skill); + + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + const ESM::Attribute* attr = + esmStore.get().find(skill->mData.mAttribute); + assert(attr); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), + boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + } + + mSkillWidgetMap[skillId] = widget; + } +} + +void StatsWindow::updateSkillArea() +{ + mChanged = false; + + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); + mClientHeight = 0; + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::NPC *player = + world->getPlayer().getPlayer().get()->mBase; + + // race tooltip + const ESM::Race* playerRace = store.get().find(player->mRace); + + MyGUI::Widget* raceWidget; + getWidget(raceWidget, "RaceText"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + getWidget(raceWidget, "Race_str"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + + // class tooltip + MyGUI::Widget* classWidget; + + const ESM::Class *playerClass = + store.get().find(player->mClass); + + getWidget(classWidget, "ClassText"); + ToolTips::createClassToolTip(classWidget, *playerClass); + getWidget(classWidget, "Class_str"); + ToolTips::createClassToolTip(classWidget, *playerClass); + + if (!mFactions.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + std::set& expelled = PCstats.getExpelled (); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); + FactionList::const_iterator end = mFactions.end(); + for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + { + const ESM::Faction *faction = + store.get().find(it->first); + MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); + + std::string text; + + text += std::string("#DDC79E") + faction->mName; + + if (expelled.find(it->first) != expelled.end()) + text += "\n#{sExpelled}"; + else + { + text += std::string("\n#BF9959") + faction->mRanks[it->second]; + + if (it->second < 9) + { + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + + ESM::RankData rankData = faction->mData.mRankData[it->second+1]; + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.mSkill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + if (rankData.mSkill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); + } + } + + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "TextToolTip"); + w->setUserString("Caption_Text", text); + } + } + + if (!mBirthSignId.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); + const ESM::BirthSign *sign = + store.get().find(mBirthSignId); + MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); + + ToolTips::createBirthsignToolTip(w, mBirthSignId); + } + + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), + boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); + } + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), + boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); + } + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); +} + +void StatsWindow::onPinToggled() +{ + MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); +} diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp new file mode 100644 index 0000000000..93e26e063d --- /dev/null +++ b/apps/openmw/mwgui/statswindow.hpp @@ -0,0 +1,83 @@ +#ifndef MWGUI_STATS_WINDOW_H +#define MWGUI_STATS_WINDOW_H + +#include "../mwworld/esmstore.hpp" + +#include +#include +#include +#include + +#include "../mwmechanics/stat.hpp" +#include "windowpinnablebase.hpp" + +namespace MWGui +{ + class WindowManager; + + class StatsWindow : public WindowPinnableBase + { + public: + typedef std::map FactionList; + + typedef std::vector SkillList; + + StatsWindow(MWBase::WindowManager& parWindowManager); + + /// automatically updates all the data in the stats window, but only if it has changed. + void onFrame(); + + void setBar(const std::string& name, const std::string& tname, int val, int max); + void setPlayerName(const std::string& playerName); + + /// Set value for the given ID. + void setValue (const std::string& id, const MWMechanics::Stat& value); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setValue (const std::string& id, const std::string& value); + void setValue (const std::string& id, int value); + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); + + void configureSkills (const SkillList& major, const SkillList& minor); + void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } + void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } + void updateSkillArea(); + + private: + void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + + void setFactions (const FactionList& factions); + void setExpelled (const std::set& expelled); + void setBirthSign (const std::string &signId); + + void onWindowResize(MyGUI::Window* window); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + + static const int sLineHeight; + + MyGUI::Widget* mLeftPane; + MyGUI::Widget* mRightPane; + + MyGUI::ScrollView* mSkillView; + int mLastPos, mClientHeight; + + SkillList mMajorSkills, mMinorSkills, mMiscSkills; + std::map > mSkillValues; + std::map mSkillWidgetMap; + std::map mFactionWidgetMap; + FactionList mFactions; ///< Stores a list of factions and the current rank + std::string mBirthSignId; + int mReputation, mBounty; + std::vector mSkillWidgets; //< Skills and other information + std::set mExpelled; + + bool mChanged; + + protected: + virtual void onPinToggled(); + }; +} +#endif diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp new file mode 100644 index 0000000000..071971befb --- /dev/null +++ b/apps/openmw/mwgui/textinput.cpp @@ -0,0 +1,70 @@ +#include "textinput.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +using namespace MWGui; + +TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) + : WindowModal("openmw_text_input.layout", parWindowManager) +{ + // Centre dialog + center(); + + getWidget(mTextEdit, "TextEdit"); + mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); +} + +void TextInputDialog::setNextButtonShow(bool shown) +{ + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); +} + +void TextInputDialog::setTextLabel(const std::string &label) +{ + setText("LabelT", label); +} + +void TextInputDialog::open() +{ + WindowModal::open(); + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); +} + +// widget controls + +void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) +{ + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); +} + +void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) +{ + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); +} diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp new file mode 100644 index 0000000000..6b371bae74 --- /dev/null +++ b/apps/openmw/mwgui/textinput.hpp @@ -0,0 +1,33 @@ +#ifndef MWGUI_TEXT_INPUT_H +#define MWGUI_TEXT_INPUT_H + +#include "windowbase.hpp" + +namespace MWGui +{ + class WindowManager; +} + +namespace MWGui +{ + class TextInputDialog : public WindowModal + { + public: + TextInputDialog(MWBase::WindowManager& parWindowManager); + + std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } + void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } + + void setNextButtonShow(bool shown); + void setTextLabel(const std::string &label); + virtual void open(); + + protected: + void onOkClicked(MyGUI::Widget* _sender); + void onTextAccepted(MyGUI::Edit* _sender); + + private: + MyGUI::EditBox* mTextEdit; + }; +} +#endif diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9292e60e5c..7730019e83 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -12,7 +12,7 @@ #include "../mwworld/class.hpp" -#include "map_window.hpp" +#include "mapwindow.hpp" #include "widgets.hpp" #include "inventorywindow.hpp" @@ -22,7 +22,6 @@ using namespace MyGUI; ToolTips::ToolTips(MWBase::WindowManager* windowManager) : Layout("openmw_tooltips.layout") , mGameMode(true) - , mWindowManager(windowManager) , mFullHelp(false) , mEnabled(true) , mFocusToolTipX(0.0) @@ -81,9 +80,9 @@ void ToolTips::onFrame(float frameDuration) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Console) - || (mWindowManager->getMode() == GM_Container) - || (mWindowManager->getMode() == GM_Inventory))) + if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); @@ -93,7 +92,7 @@ void ToolTips::onFrame(float frameDuration) const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); IntSize tooltipSize; - if ((!objectclass.hasToolTip(mFocusObject))&&(mWindowManager->getMode() == GM_Console)) + if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) { setCoord(0, 0, 300, 300); mDynamicToolTipBox->setVisible(true); @@ -139,7 +138,7 @@ void ToolTips::onFrame(float frameDuration) mLastMouseX = mousePos.left; mLastMouseY = mousePos.top; - + if (mRemainingDelay > 0) return; @@ -167,8 +166,8 @@ void ToolTips::onFrame(float frameDuration) { return; } - - + + // special handling for markers on the local map: the tooltip should only be visible // if the marker is not hidden due to the fog of war. if (focus->getUserString ("IsMarker") == "true") @@ -190,11 +189,11 @@ void ToolTips::onFrame(float frameDuration) } else if (type == "AvatarItemSelection") { - MyGUI::IntCoord avatarPos = mWindowManager->getInventoryWindow ()->getAvatarScreenCoord (); + MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); - MWWorld::Ptr item = mWindowManager->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); mFocusObject = item; if (!mFocusObject.isEmpty ()) @@ -346,7 +345,7 @@ void ToolTips::findImageExtension(std::string& image) } IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) -{ +{ mDynamicToolTipBox->setVisible(true); std::string caption = info.caption; @@ -380,7 +379,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) setCoord(0, 0, 300, 300); const IntPoint padding(8, 8); - + const int maximumWidth = 500; const int imageCaptionHPadding = (caption != "" ? 8 : 0); @@ -424,7 +423,6 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEffectsWidget"); - effectsWidget->setWindowManager(mWindowManager); effectsWidget->setEffectList(info.effects); std::vector effectItems; @@ -444,7 +442,6 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); - enchantWidget->setWindowManager(mWindowManager); enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); std::vector enchantEffectItems; @@ -493,7 +490,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) (captionHeight-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); - + //if its too long we do hscroll with the caption if (captionSize.width > maximumWidth) { diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index da5a35221c..e4fcb310c8 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -82,8 +82,6 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - MWBase::WindowManager* mWindowManager; - MWWorld::Ptr mFocusObject; void findImageExtension(std::string& image); @@ -96,9 +94,9 @@ namespace MWGui float mFocusToolTipX; float mFocusToolTipY; - + int mHorizontalScrollIndex; - + float mDelay; float mRemainingDelay; // remaining time until tooltip will show diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 81a29e69bd..718e6378bb 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -85,7 +85,7 @@ namespace MWGui mCurrentBalance = 0; mCurrentMerchantOffer = 0; - mWindowManager.getInventoryWindow()->startTrade(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->startTrade(); mBoughtItems.clear(); @@ -127,7 +127,7 @@ namespace MWGui { bool goldFound = false; MWWorld::Ptr gold; - MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore(); + MWWorld::ContainerStore& playerStore = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getContainerStore(); for (MWWorld::ContainerStoreIterator it = playerStore.begin(); it != playerStore.end(); ++it) @@ -172,7 +172,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); // were there any items traded at all? - MWWorld::ContainerStore& playerBought = mWindowManager.getInventoryWindow()->getBoughtItems(); + MWWorld::ContainerStore& playerBought = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getBoughtItems(); MWWorld::ContainerStore& merchantBought = getBoughtItems(); if (playerBought.begin() == playerBought.end() && merchantBought.begin() == merchantBought.end()) { @@ -183,7 +183,7 @@ namespace MWGui } // check if the player can afford this - if (mCurrentBalance < 0 && mWindowManager.getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) + if (mCurrentBalance < 0 && MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) { // user notification MWBase::Environment::get().getWindowManager()-> @@ -258,7 +258,7 @@ namespace MWGui // success! make the item transfer. transferBoughtItems(); - mWindowManager.getInventoryWindow()->transferBoughtItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->transferBoughtItems(); // add or remove gold from the player. if (mCurrentBalance != 0) @@ -267,17 +267,17 @@ namespace MWGui std::string sound = "Item Gold Up"; MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - mWindowManager.removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { // i give you back your stuff! - returnBoughtItems(mWindowManager.getInventoryWindow()->getContainerStore()); + returnBoughtItems(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getContainerStore()); // now gimme back my stuff! - mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); - mWindowManager.removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) @@ -321,7 +321,7 @@ namespace MWGui void TradeWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); if (mCurrentBalance > 0) { @@ -422,8 +422,8 @@ namespace MWGui void TradeWindow::onReferenceUnavailable() { // remove both Trade and Dialogue (since you always trade with the NPC/creature that you have previously talked to) - mWindowManager.removeGuiMode(GM_Barter); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } int TradeWindow::getMerchantGold() diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 2e05d03d51..111c0935fe 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -2,7 +2,7 @@ #define MWGUI_TRADEWINDOW_H #include "container.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 601b44d6c9..c2b543a4fd 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,7 @@ namespace MWGui { mPtr = actor; - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(actor).getNpcStats (actor); @@ -82,7 +82,7 @@ namespace MWGui int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer (mPtr,pcStats.getSkill (bestSkills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); - std::string skin = (price > mWindowManager.getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton"; + std::string skin = (price > MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton"; MyGUI::Button* button = mTrainingOptions->createWidget(skin, MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default); @@ -102,12 +102,12 @@ namespace MWGui void TrainingWindow::onReferenceUnavailable () { - mWindowManager.removeGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Training); } void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender) { - mWindowManager.removeGuiMode (GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); } void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender) @@ -123,13 +123,13 @@ namespace MWGui int price = pcStats.getSkill (skillId).getBase() * store.get().find("iTrainingMod")->getInt (); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - if (mWindowManager.getInventoryWindow()->getPlayerGold()getInventoryWindow()->getPlayerGold()messageBox ("#{sServiceTrainingWords}"); return; } @@ -141,11 +141,11 @@ namespace MWGui pcStats.increaseSkill (skillId, *class_, true); // remove gold - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); // go back to game mode - mWindowManager.removeGuiMode (GM_Training); - mWindowManager.removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); // advance time MWBase::Environment::get().getWorld ()->advanceTime (2); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index f2ef1714ee..d6be60ae67 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_TRAININGWINDOW_H #define MWGUI_TRAININGWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 465f588b8a..b710171669 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -71,7 +71,7 @@ namespace MWGui price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - MyGUI::Button* toAdd = mDestinationsView->createWidget((price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); + MyGUI::Button* toAdd = mDestinationsView->createWidget((price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); mCurrentY += sLineHeight; if(interior) toAdd->setUserString("interior","y"); @@ -129,10 +129,10 @@ namespace MWGui int price; iss >> price; - if (mWindowManager.getInventoryWindow()->getPlayerGold()getInventoryWindow()->getPlayerGold()addOrRemoveGold (-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow ()->addOrRemoveGold (-price); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -156,20 +156,20 @@ namespace MWGui MWBase::Environment::get().getWorld()->advanceTime(time); } MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); - mWindowManager.removeGuiMode(GM_Travel); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0); MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(1); } void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); } void TravelWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, @@ -178,8 +178,8 @@ namespace MWGui void TravelWindow::onReferenceUnavailable() { - mWindowManager.removeGuiMode(GM_Travel); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index cc3d6a31f7..61b724910c 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -2,7 +2,7 @@ #define MWGUI_TravelWINDOW_H #include "container.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 09eb5c914e..69dfa10b4d 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -75,7 +75,7 @@ namespace MWGui { if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } int canRest = MWBase::Environment::get().getWorld ()->canRest (); @@ -83,8 +83,8 @@ namespace MWGui if (canRest == 2) { // resting underwater or mid-air not allowed - mWindowManager.messageBox ("#{sNotifyMessage1}"); - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage1}"); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } setCanRest(canRest == 0); @@ -212,7 +212,7 @@ namespace MWGui void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) @@ -263,8 +263,8 @@ namespace MWGui { MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.2); mProgressBar.setVisible (false); - mWindowManager.removeGuiMode (GM_Rest); - mWindowManager.removeGuiMode (GM_RestBed); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); mWaiting = false; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -273,7 +273,7 @@ namespace MWGui // trigger levelup if possible if (mSleeping && pcstats.getLevelProgress () >= 10) { - mWindowManager.pushGuiMode (GM_Levelup); + MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); } } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index c102d0fc67..4510e665b3 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_WAIT_DIALOG_H #define MWGUI_WAIT_DIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index e822e047ea..3801ae6f7a 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -218,8 +218,7 @@ void MWAttribute::initialiseOverride() /* MWSpell */ MWSpell::MWSpell() - : mWindowManager(NULL) - , mSpellNameWidget(NULL) + : mSpellNameWidget(NULL) { } @@ -242,7 +241,6 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::W for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - effect->setWindowManager(mWindowManager); SpellEffectParams params; params.mEffectID = it->mEffectID; params.mSkill = it->mSkill; @@ -262,7 +260,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::W void MWSpell::updateWidgets() { - if (mSpellNameWidget && mWindowManager) + if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -289,8 +287,7 @@ MWSpell::~MWSpell() /* MWEffectList */ MWEffectList::MWEffectList() - : mWindowManager(NULL) - , mEffectList(0) + : mEffectList(0) { } @@ -311,7 +308,6 @@ void MWEffectList::createEffectWidgets(std::vector &effects, MyG it != mEffectList.end(); ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - effect->setWindowManager(mWindowManager); it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; effect->setSpellEffect(*it); @@ -378,8 +374,7 @@ SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() - : mWindowManager(NULL) - , mImageWidget(NULL) + : mImageWidget(NULL) , mTextWidget(NULL) , mRequestedWidth(0) { @@ -409,22 +404,22 @@ void MWSpellEffect::updateWidgets() assert(magicEffect); - std::string pt = mWindowManager->getGameSettingString("spoint", ""); - std::string pts = mWindowManager->getGameSettingString("spoints", ""); - std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " "; - std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); - std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); + std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); + std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; + std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); + std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); - std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); + std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) { - spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); } if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) { - spellLine += " " + mWindowManager->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); } if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) @@ -442,7 +437,7 @@ void MWSpellEffect::updateWidgets() { if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) { - spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); } if (mEffectParams.mArea > 0) @@ -453,13 +448,13 @@ void MWSpellEffect::updateWidgets() // potions have no target if (!mEffectParams.mNoTarget) { - std::string on = mWindowManager->getGameSettingString("sonword", ""); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); if (mEffectParams.mRange == ESM::RT_Self) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); else if (mEffectParams.mRange == ESM::RT_Touch) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); else if (mEffectParams.mRange == ESM::RT_Target) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); } } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 784537c42a..26ca750667 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -94,7 +94,6 @@ namespace MWGui typedef MWMechanics::Stat SkillValue; - void setWindowManager(MWBase::WindowManager *m) { mManager = m; } /// \todo remove void setSkillId(ESM::Skill::SkillEnum skillId); void setSkillNumber(int skillId); void setSkillValue(const SkillValue& value); @@ -138,7 +137,6 @@ namespace MWGui typedef MWMechanics::Stat AttributeValue; - void setWindowManager(MWBase::WindowManager *m) { mManager = m; } void setAttributeId(int attributeId); void setAttributeValue(const AttributeValue& value); @@ -185,7 +183,6 @@ namespace MWGui typedef MWMechanics::Stat SpellValue; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellId(const std::string &id); /** @@ -207,7 +204,6 @@ namespace MWGui private: void updateWidgets(); - MWBase::WindowManager* mWindowManager; std::string mId; MyGUI::TextBox* mSpellNameWidget; }; @@ -227,7 +223,6 @@ namespace MWGui EF_Constant = 0x02 // constant effect means that duration will not be displayed }; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setEffectList(const SpellEffectList& list); static SpellEffectList effectListFromESM(const ESM::EffectList* effects); @@ -249,7 +244,6 @@ namespace MWGui private: void updateWidgets(); - MWBase::WindowManager* mWindowManager; SpellEffectList mEffectList; }; typedef MWEffectList* MWEffectListPtr; @@ -262,7 +256,6 @@ namespace MWGui typedef ESM::ENAMstruct SpellEffectValue; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellEffect(const SpellEffectParams& params); int getRequestedWidth() const { return mRequestedWidth; } @@ -276,7 +269,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager* mWindowManager; SpellEffectParams mEffectParams; MyGUI::ImageBox* mImageWidget; MyGUI::TextBox* mTextWidget; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp new file mode 100644 index 0000000000..cb3d4ea8c8 --- /dev/null +++ b/apps/openmw/mwgui/windowbase.cpp @@ -0,0 +1,54 @@ +#include "windowbase.hpp" + +#include + +#include "../mwbase/windowmanager.hpp" + +using namespace MWGui; + +WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : Layout(parLayout) +{ +} + +void WindowBase::setVisible(bool visible) +{ + bool wasVisible = mMainWidget->getVisible(); + mMainWidget->setVisible(visible); + + if (visible) + open(); + else if (wasVisible && !visible) + close(); +} + +void WindowBase::center() +{ + // Centre dialog + + // MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + // Note by scrawl: The following works more reliably in the case when the window was _just_ + // resized and MyGUI RenderManager doesn't know about the new size yet + MyGUI::IntSize gameWindowSize = MyGUI::IntSize(Settings::Manager::getInt("resolution x", "Video"), + Settings::Manager::getInt("resolution y", "Video")); + + MyGUI::IntCoord coord = mMainWidget->getCoord(); + coord.left = (gameWindowSize.width - coord.width)/2; + coord.top = (gameWindowSize.height - coord.height)/2; + mMainWidget->setCoord(coord); +} + +WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : WindowBase(parLayout, parWindowManager) +{ +} + +void WindowModal::open() +{ + MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); +} + +void WindowModal::close() +{ + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); +} diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp new file mode 100644 index 0000000000..a2cb731fee --- /dev/null +++ b/apps/openmw/mwgui/windowbase.hpp @@ -0,0 +1,47 @@ +#ifndef MWGUI_WINDOW_BASE_H +#define MWGUI_WINDOW_BASE_H + +#include + +namespace MWBase +{ + class WindowManager; +} + +namespace MWGui +{ + class WindowManager; + + class WindowBase: public OEngine::GUI::Layout + { + public: + WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + + // Events + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; + + virtual void open() {} + virtual void close () {} + virtual void setVisible(bool visible); + void center(); + + /** Event : Dialog finished, OK button clicked.\n + signature : void method()\n + */ + EventHandle_WindowBase eventDone; + }; + + + /* + * "Modal" windows cause the rest of the interface to be unaccessible while they are visible + */ + class WindowModal : public WindowBase + { + public: + WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + virtual void open(); + virtual void close(); + }; +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f994683a66..bcde82e966 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -21,12 +21,12 @@ #include "console.hpp" #include "journalwindow.hpp" #include "charactercreation.hpp" -#include "text_input.hpp" +#include "textinput.hpp" #include "review.hpp" #include "dialogue.hpp" -#include "dialogue_history.hpp" -#include "map_window.hpp" -#include "stats_window.hpp" +#include "dialoguehistory.hpp" +#include "mapwindow.hpp" +#include "statswindow.hpp" #include "messagebox.hpp" #include "container.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp new file mode 100644 index 0000000000..54ed082cf9 --- /dev/null +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -0,0 +1,28 @@ +#include "windowpinnablebase.hpp" + +#include "../mwbase/windowmanager.hpp" + +#include "exposedwindow.hpp" + +using namespace MWGui; + +WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) +{ + ExposedWindow* window = static_cast(mMainWidget); + mPinButton = window->getSkinWidget ("Button"); + + mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); +} + +void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) +{ + mPinned = !mPinned; + + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); + + onPinToggled(); +} diff --git a/apps/openmw/mwgui/windowpinnablebase.hpp b/apps/openmw/mwgui/windowpinnablebase.hpp new file mode 100644 index 0000000000..657e8142f1 --- /dev/null +++ b/apps/openmw/mwgui/windowpinnablebase.hpp @@ -0,0 +1,28 @@ +#ifndef MWGUI_WINDOW_PINNABLE_BASE_H +#define MWGUI_WINDOW_PINNABLE_BASE_H + +#include "windowbase.hpp" + +namespace MWGui +{ + class WindowManager; + + class WindowPinnableBase: public WindowBase + { + public: + WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + bool pinned() { return mPinned; } + + private: + void onPinButtonClicked(MyGUI::Widget* _sender); + + protected: + virtual void onPinToggled() = 0; + + MyGUI::Widget* mPinButton; + bool mPinned; + bool mVisible; + }; +} + +#endif From ad49d1ecab8be0fdd863a5f747f5a680bf1fdc5a Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 10 Apr 2013 15:24:20 +0200 Subject: [PATCH 1032/1483] Sixth minor fix --- apps/openmw/mwclass/armor.cpp | 6 +++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 6 +++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 18 +++++++++--------- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/actionequip.cpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a14b2667e1..d257c87619 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,12 +292,12 @@ namespace MWClass ref->mBase = record; } - int Armor::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); // slots that this item can be equipped in - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::string npcRace = npc.get()->mBase->mRace; @@ -309,7 +309,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = item.get()->mBase->mParts.mParts; + std::vector parts = ptr.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 96c72848cc..1b99e51331 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 58c4a2c5c6..b4e6e61f65 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,10 +238,10 @@ namespace MWClass ref->mBase = record; } - int Clothing::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { // slots that this item can be equipped in - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::string npcRace = npc.get()->mBase->mRace; @@ -253,7 +253,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = item.get()->mBase->mParts.mParts; + std::vector parts = ptr.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index eb8d801996..71e01e8187 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a0cacaf6bd..e534a65c2a 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,9 +384,9 @@ namespace MWClass ref->mBase = record; } - int Weapon::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); @@ -394,13 +394,13 @@ namespace MWClass { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if(item.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - item.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - item.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - item.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + if(ptr.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + ptr.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + ptr.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { return 2; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 01686b09cc..6c3f32abef 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index fd35d0dd3c..84d1a3d158 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -21,7 +21,7 @@ namespace MWWorld MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + switch(MWWorld::Class::get (object).canBeEquipped (object, actor)) { case 0: return; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a0067f5d2e..d7ff350141 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,7 +259,7 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - int Class::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { return 1; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 362a8bc9ca..484004aca5 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,7 +242,7 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual Ptr diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 782e3f920f..5495d6a021 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -186,7 +186,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - switch(MWWorld::Class::get (test).canBeEquipped (npc, test)) + switch(MWWorld::Class::get (test).canBeEquipped (test, npc)) { case 0: continue; From d768f6b57e2e4b992861a18dedf9e39c6e79b702 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 13:05:15 -0400 Subject: [PATCH 1033/1483] Deleted *_* files in MwGui, builds. --- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/mwgui/dialogue_history.cpp | 76 --- apps/openmw/mwgui/dialogue_history.hpp | 19 - apps/openmw/mwgui/map_window.cpp | 446 ---------------- apps/openmw/mwgui/map_window.hpp | 107 ---- apps/openmw/mwgui/stats_window.cpp | 580 --------------------- apps/openmw/mwgui/stats_window.hpp | 83 --- apps/openmw/mwgui/text_input.cpp | 69 --- apps/openmw/mwgui/text_input.hpp | 36 -- apps/openmw/mwgui/window_base.cpp | 55 -- apps/openmw/mwgui/window_base.hpp | 51 -- apps/openmw/mwgui/window_pinnable_base.cpp | 28 - apps/openmw/mwgui/window_pinnable_base.hpp | 28 - 13 files changed, 3 insertions(+), 1581 deletions(-) delete mode 100644 apps/openmw/mwgui/dialogue_history.cpp delete mode 100644 apps/openmw/mwgui/dialogue_history.hpp delete mode 100644 apps/openmw/mwgui/map_window.cpp delete mode 100644 apps/openmw/mwgui/map_window.hpp delete mode 100644 apps/openmw/mwgui/stats_window.cpp delete mode 100644 apps/openmw/mwgui/stats_window.hpp delete mode 100644 apps/openmw/mwgui/text_input.cpp delete mode 100644 apps/openmw/mwgui/text_input.hpp delete mode 100644 apps/openmw/mwgui/window_base.cpp delete mode 100644 apps/openmw/mwgui/window_base.hpp delete mode 100644 apps/openmw/mwgui/window_pinnable_base.cpp delete mode 100644 apps/openmw/mwgui/window_pinnable_base.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8a0030be42..b3c3f4134c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -24,9 +24,9 @@ add_openmw_dir (mwinput ) add_openmw_dir (mwgui - text_input widgets race class birth review windowmanagerimp console dialogue - dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base tooltips scrollwindow bookwindow list + textinput widgets race class birth review windowmanagerimp console dialogue + dialoguehistory windowbase statswindow messagebox journalwindow charactercreation + mapwindow windowpinnablebase tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog diff --git a/apps/openmw/mwgui/dialogue_history.cpp b/apps/openmw/mwgui/dialogue_history.cpp deleted file mode 100644 index 13f72545e2..0000000000 --- a/apps/openmw/mwgui/dialogue_history.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "dialogue_history.hpp" - -#include "../mwbase/windowmanager.hpp" - -#include "widgets.hpp" - -#include "../mwworld/esmstore.hpp" - -#include -#include - -#include -#include - -using namespace MWGui; -using namespace Widgets; - -MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) -{ - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::TextIterator iterator(getCaption()); - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if (pos < _pos) - continue; - else if (pos == _pos) - break; - } - return colour; -} - -MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) -{ - bool breakOnNext = false; - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::UString colour2 = colour; - MyGUI::TextIterator iterator(getCaption()); - MyGUI::TextIterator col_start = iterator; - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if(colour != colour2) - { - if(breakOnNext) - { - return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); - } - col_start = iterator; - colour2 = colour; - } - if (pos < _pos) - continue; - else if (pos == _pos) - { - breakOnNext = true; - } - } - return ""; -} - -void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) -{ - MyGUI::UString head("\n#D8C09A"); - head.append(parText); - head.append("#B29154\n"); - addText(head); -} - -void DialogueHistory::addDialogText(const MyGUI::UString& parText) -{ - addText(parText); - addText("\n"); -} diff --git a/apps/openmw/mwgui/dialogue_history.hpp b/apps/openmw/mwgui/dialogue_history.hpp deleted file mode 100644 index c37504af77..0000000000 --- a/apps/openmw/mwgui/dialogue_history.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MWGUI_DIALOGE_HISTORY_H -#define MWGUI_DIALOGE_HISTORY_H -#include - -namespace MWGui -{ - class DialogueHistory : public MyGUI::EditBox - { - MYGUI_RTTI_DERIVED( DialogueHistory ) - public: - Widget* getClient() { return mClient; } - MyGUI::UString getColorAtPos(size_t _pos); - MyGUI::UString getColorTextAt(size_t _pos); - void addDialogHeading(const MyGUI::UString& parText); - void addDialogText(const MyGUI::UString& parText); - }; -} -#endif - diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp deleted file mode 100644 index d0f3f921e5..0000000000 --- a/apps/openmw/mwgui/map_window.cpp +++ /dev/null @@ -1,446 +0,0 @@ -#include "map_window.hpp" - -#include - -#include -#include -#include - -#include - -#include "../mwbase/windowmanager.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" -#include "../mwworld/player.hpp" - -#include "../mwrender/globalmap.hpp" - -#include "widgets.hpp" - -using namespace MWGui; - -LocalMapBase::LocalMapBase() - : mCurX(0) - , mCurY(0) - , mInterior(false) - , mFogOfWar(true) - , mLocalMap(NULL) - , mMapDragAndDrop(false) - , mPrefix() - , mChanged(true) - , mLayout(NULL) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) - , mLastDirectionX(0.0f) - , mLastDirectionY(0.0f) - , mCompass(NULL) -{ -} - -void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) -{ - mLocalMap = widget; - mLayout = layout; - mMapDragAndDrop = mapDragAndDrop; - mCompass = compass; - - // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each - const int widgetSize = 512; - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", - MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); - - MyGUI::ImageBox* fog = map->createWidget("ImageBox", - MyGUI::IntCoord(0, 0, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); - - if (!mMapDragAndDrop) - { - map->setNeedMouseFocus(false); - fog->setNeedMouseFocus(false); - } - - mMapWidgets.push_back(map); - mFogWidgets.push_back(fog); - } - } -} - -void LocalMapBase::setCellPrefix(const std::string& prefix) -{ - mPrefix = prefix; - mChanged = true; -} - -void LocalMapBase::toggleFogOfWar() -{ - mFogOfWar = !mFogOfWar; - applyFogOfWar(); -} - -void LocalMapBase::applyFogOfWar() -{ - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (-1*(my-1))); - MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) - : ""); - } - } - notifyMapChanged (); -} - -void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::setActiveCell(const int x, const int y, bool interior) -{ - if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell - - // clear all previous markers - for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) - { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") - { - MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); - } - } - - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - // map - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (-1*(my-1))); - - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); - else - box->setImageTexture("black.png"); - - - // door markers - - // interior map only consists of one cell, so handle the markers only once - if (interior && (mx != 2 || my != 2)) - continue; - - MWWorld::CellStore* cell; - if (interior) - cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); - else - cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); - - std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); - - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) - { - MWBase::World::DoorMarker marker = *it; - - // convert world coordinates to normalized cell coordinates - MyGUI::IntCoord widgetCoord; - float nX,nY; - int cellDx, cellDy; - if (!interior) - { - const int cellSize = 8192; - - nX = (marker.x - cellSize * (x+mx-1)) / cellSize; - nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); - } - else - { - Ogre::Vector2 position (marker.x, marker.y); - MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); - } - - static int counter = 0; - ++counter; - MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", marker.name); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); - markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); - - MarkerPosition markerPos; - markerPos.interior = interior; - markerPos.cellX = interior ? cellDx : x + mx - 1; - markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); - markerPos.nX = nX; - markerPos.nY = nY; - - markerWidget->setUserData(markerPos); - } - - - } - } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; - - // fog of war - applyFogOfWar(); - - // set the compass texture again, because MyGUI determines sorting of ImageBox widgets - // based on the last setImageTexture call - std::string tex = "textures\\compass.dds"; - mCompass->setImageTexture(""); - mCompass->setImageTexture(tex); -} - - -void LocalMapBase::setPlayerPos(const float x, const float y) -{ - if (x == mLastPositionX && y == mLastPositionY) - return; - - notifyPlayerUpdate (); - - MyGUI::IntSize size = mLocalMap->getCanvasSize(); - MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); - MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); - mLocalMap->setViewOffset(pos); - - mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); - mLastPositionX = x; - mLastPositionY = y; -} - -void LocalMapBase::setPlayerDir(const float x, const float y) -{ - if (x == mLastDirectionX && y == mLastDirectionY) - return; - - notifyPlayerUpdate (); - - MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(x,y); - rotatingSubskin->setAngle(angle); - - mLastDirectionX = x; - mLastDirectionY = y; -} - -// ------------------------------------------------------------------------------------------ - -MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) - , mGlobal(false) -{ - setCoord(500,0,320,300); - - mGlobalMapRender = new MWRender::GlobalMap(cacheDir); - mGlobalMapRender->render(); - - getWidget(mLocalMap, "LocalMap"); - getWidget(mGlobalMap, "GlobalMap"); - getWidget(mGlobalMapImage, "GlobalMapImage"); - getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); - getWidget(mPlayerArrowLocal, "CompassLocal"); - getWidget(mPlayerArrowGlobal, "CompassGlobal"); - - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); - - mGlobalMap->setVisible (false); - - getWidget(mButton, "WorldButton"); - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing("#{sWorld}"); - - getWidget(mEventBoxGlobal, "EventBoxGlobal"); - mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - getWidget(mEventBoxLocal, "EventBoxLocal"); - mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - - LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); -} - -MapWindow::~MapWindow() -{ - delete mGlobalMapRender; -} - -void MapWindow::setCellName(const std::string& cellName) -{ - setTitle("#{sCell=" + cellName + "}"); -} - -void MapWindow::addVisitedLocation(const std::string& name, int x, int y) -{ - float worldX, worldY; - mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); - - MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+6, - worldY * mGlobalMapRender->getHeight()+6, - 12, 12); - - - static int _counter=0; - MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); - ++_counter; - - markerWidget = mEventBoxGlobal->createWidget("", - widgetCoord, MyGUI::Align::Default); - markerWidget->setNeedMouseFocus (true); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); -} - -void MapWindow::cellExplored(int x, int y) -{ - mGlobalMapRender->exploreCell(x,y); -} - -void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - - MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - - if (!mGlobal) - mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); - else - mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); - - - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) -{ - mGlobal = !mGlobal; - mGlobalMap->setVisible(mGlobal); - mLocalMap->setVisible(!mGlobal); - - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); - - if (mGlobal) - globalMapUpdatePlayer (); -} - -void MapWindow::onPinToggled() -{ - mWindowManager.setMinimapVisibility(!mPinned); -} - -void MapWindow::open() -{ - mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - - for (unsigned int i=0; igetChildCount (); ++i) - { - if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") - mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); - } - - globalMapUpdatePlayer(); - - mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); -} - -void MapWindow::globalMapUpdatePlayer () -{ - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); - Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - - // for interiors, we have no choice other than using the last position & direction. - /// \todo save this last position in the savegame? - if (MWBase::Environment::get().getWorld ()->isCellExterior ()) - { - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); - - MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(dir.x, dir.y); - rotatingSubskin->setAngle(angle); - - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); - mGlobalMap->setViewOffset(viewoffs); - } -} - -void MapWindow::notifyPlayerUpdate () -{ - globalMapUpdatePlayer (); -} - -void MapWindow::notifyMapChanged () -{ - // workaround to prevent the map from drawing on top of the button - MyGUI::IntCoord oldCoord = mButton->getCoord (); - MyGUI::Gui::getInstance().destroyWidget (mButton); - mButton = mMainWidget->createWidget("MW_Button", - oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); - mButton->setProperty ("ExpandDirection", "Left"); - - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); -} diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp deleted file mode 100644 index 39770a7a26..0000000000 --- a/apps/openmw/mwgui/map_window.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef MWGUI_MAPWINDOW_H -#define MWGUI_MAPWINDOW_H - -#include "window_pinnable_base.hpp" - -namespace MWRender -{ - class GlobalMap; -} - -namespace MWGui -{ - class LocalMapBase - { - public: - LocalMapBase(); - void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false); - - void setCellPrefix(const std::string& prefix); - void setActiveCell(const int x, const int y, bool interior=false); - void setPlayerDir(const float x, const float y); - void setPlayerPos(const float x, const float y); - - void toggleFogOfWar(); - - struct MarkerPosition - { - bool interior; - int cellX; - int cellY; - float nX; - float nY; - }; - - protected: - int mCurX, mCurY; - bool mInterior; - MyGUI::ScrollView* mLocalMap; - MyGUI::ImageBox* mCompass; - std::string mPrefix; - bool mChanged; - bool mFogOfWar; - - std::vector mMapWidgets; - std::vector mFogWidgets; - - void applyFogOfWar(); - - void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); - void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); - - virtual void notifyPlayerUpdate() {} - virtual void notifyMapChanged() {} - - OEngine::GUI::Layout* mLayout; - - bool mMapDragAndDrop; - - float mLastPositionX; - float mLastPositionY; - float mLastDirectionX; - float mLastDirectionY; - }; - - class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase - { - public: - MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); - virtual ~MapWindow(); - - void setCellName(const std::string& cellName); - - void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map - void cellExplored(int x, int y); - - virtual void open(); - - private: - void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); - void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); - void onWorldButtonClicked(MyGUI::Widget* _sender); - - void globalMapUpdatePlayer(); - - MyGUI::ScrollView* mGlobalMap; - MyGUI::ImageBox* mGlobalMapImage; - MyGUI::ImageBox* mGlobalMapOverlay; - MyGUI::ImageBox* mPlayerArrowLocal; - MyGUI::ImageBox* mPlayerArrowGlobal; - MyGUI::Button* mButton; - MyGUI::IntPoint mLastDragPos; - bool mGlobal; - - MyGUI::Button* mEventBoxGlobal; - MyGUI::Button* mEventBoxLocal; - - MWRender::GlobalMap* mGlobalMapRender; - - protected: - virtual void onPinToggled(); - - virtual void notifyPlayerUpdate(); - virtual void notifyMapChanged(); - - }; -} -#endif diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp deleted file mode 100644 index 0678e98919..0000000000 --- a/apps/openmw/mwgui/stats_window.cpp +++ /dev/null @@ -1,580 +0,0 @@ -#include "stats_window.hpp" - -#include -#include -#include - -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwworld/player.hpp" -#include "../mwworld/class.hpp" - -#include "../mwmechanics/npcstats.hpp" - -#include "tooltips.hpp" - - -using namespace MWGui; -const int StatsWindow::sLineHeight = 18; - -StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) - , mSkillView(NULL) - , mClientHeight(0) - , mMajorSkills() - , mMinorSkills() - , mMiscSkills() - , mSkillValues() - , mSkillWidgetMap() - , mFactionWidgetMap() - , mFactions() - , mBirthSignId() - , mReputation(0) - , mBounty(0) - , mSkillWidgets() - , mChanged(true) -{ - setCoord(0,0,498, 342); - - const char *names[][2] = - { - { "Attrib1", "sAttributeStrength" }, - { "Attrib2", "sAttributeIntelligence" }, - { "Attrib3", "sAttributeWillpower" }, - { "Attrib4", "sAttributeAgility" }, - { "Attrib5", "sAttributeSpeed" }, - { "Attrib6", "sAttributeEndurance" }, - { "Attrib7", "sAttributePersonality" }, - { "Attrib8", "sAttributeLuck" }, - { 0, 0 } - }; - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for (int i=0; names[i][0]; ++i) - { - setText (names[i][0], store.get().find (names[i][1])->getString()); - } - - getWidget(mSkillView, "SkillView"); - getWidget(mLeftPane, "LeftPane"); - getWidget(mRightPane, "RightPane"); - - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); - } - - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); -} - -void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); -} - -void StatsWindow::onWindowResize(MyGUI::Window* window) -{ - mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); - mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) -{ - MyGUI::ProgressPtr pt; - getWidget(pt, name); - pt->setProgressRange(max); - pt->setProgressPosition(val); - - std::stringstream out; - out << val << "/" << max; - setText(tname, out.str().c_str()); -} - -void StatsWindow::setPlayerName(const std::string& playerName) -{ - static_cast(mMainWidget)->setCaption(playerName); - adjustWindowCaption(); -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 - }; - - for (int i=0; ids[i]; ++i) - if (ids[i]==id) - { - std::ostringstream valueString; - valueString << value.getModified(); - setText (id, valueString.str()); - - MyGUI::TextBox* box; - getWidget(box, id); - - if (value.getModified()>value.getBase()) - box->_setWidgetState("increased"); - else if (value.getModified()_setWidgetState("decreased"); - else - box->_setWidgetState("normal"); - - break; - } -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = - { - "HBar", "MBar", "FBar", - 0 - }; - - for (int i=0; ids[i]; ++i) - { - if (ids[i]==id) - { - std::string id (ids[i]); - setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); - - // health, magicka, fatigue tooltip - MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - if (i==0) - { - getWidget(w, "Health"); - w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); - } - else if (i==1) - { - getWidget(w, "Magicka"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); - } - else if (i==2) - { - getWidget(w, "Fatigue"); - w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); - } - } - } -} - -void StatsWindow::setValue (const std::string& id, const std::string& value) -{ - if (id=="name") - setPlayerName (value); - else if (id=="race") - setText ("RaceText", value); - else if (id=="class") - setText ("ClassText", value); -} - -void StatsWindow::setValue (const std::string& id, int value) -{ - if (id=="level") - { - std::ostringstream text; - text << value; - setText("LevelText", text.str()); - } -} - -void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) -{ - mSkillValues[parSkill] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } -} - -void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); - } - - updateSkillArea(); -} - -void StatsWindow::onFrame () -{ - if (!mMainWidget->getVisible()) - return; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - - // level progress - MyGUI::Widget* levelWidget; - for (int i=0; i<2; ++i) - { - getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); - levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); - levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); - } - - setFactions(PCstats.getFactionRanks()); - setExpelled(PCstats.getExpelled ()); - - const std::string &signId = - MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); - - setBirthSign(signId); - setReputation (PCstats.getReputation ()); - setBounty (PCstats.getBounty ()); - - if (mChanged) - updateSkillArea(); -} - -void StatsWindow::setFactions (const FactionList& factions) -{ - if (mFactions != factions) - { - mFactions = factions; - mChanged = true; - } -} - -void StatsWindow::setExpelled (const std::set& expelled) -{ - if (mExpelled != expelled) - { - mExpelled = expelled; - mChanged = true; - } -} - -void StatsWindow::setBirthSign (const std::string& signId) -{ - if (signId != mBirthSignId) - { - mBirthSignId = signId; - mChanged = true; - } -} - -void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", - MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", - MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - groupWidget->setCaption(label); - groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox *skillNameWidget, *skillValueWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillNameWidget; -} - -void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); - } - - addGroup(mWindowManager.getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) - { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - int progressPercent = (modified - float(static_cast(modified))) * 100; - - const MWWorld::ESMStore &esmStore = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Skill* skill = esmStore.get().find(skillId); - assert(skill); - - std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; - - const ESM::Attribute* attr = - esmStore.get().find(skill->mData.mAttribute); - assert(attr); - - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), - boost::lexical_cast(static_cast(modified)), state, coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); - } - - mSkillWidgetMap[skillId] = widget; - } -} - -void StatsWindow::updateSkillArea() -{ - mChanged = false; - - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillWidgets.clear(); - - mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); - mClientHeight = 0; - - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); - - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); - - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); - - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - - MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::ESMStore &store = world->getStore(); - const ESM::NPC *player = - world->getPlayer().getPlayer().get()->mBase; - - // race tooltip - const ESM::Race* playerRace = store.get().find(player->mRace); - - MyGUI::Widget* raceWidget; - getWidget(raceWidget, "RaceText"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - getWidget(raceWidget, "Race_str"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - - // class tooltip - MyGUI::Widget* classWidget; - - const ESM::Class *playerClass = - store.get().find(player->mClass); - - getWidget(classWidget, "ClassText"); - ToolTips::createClassToolTip(classWidget, *playerClass); - getWidget(classWidget, "Class_str"); - ToolTips::createClassToolTip(classWidget, *playerClass); - - if (!mFactions.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - std::set& expelled = PCstats.getExpelled (); - - addGroup(mWindowManager.getGameSettingString("sFaction", "Faction"), coord1, coord2); - FactionList::const_iterator end = mFactions.end(); - for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) - { - const ESM::Faction *faction = - store.get().find(it->first); - MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); - - std::string text; - - text += std::string("#DDC79E") + faction->mName; - - if (expelled.find(it->first) != expelled.end()) - text += "\n#{sExpelled}"; - else - { - text += std::string("\n#BF9959") + faction->mRanks[it->second]; - - if (it->second < 9) - { - // player doesn't have max rank yet - text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; - - ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - assert(attr1 && attr2); - - text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); - - text += "\n\n#DDC79E#{sFavoriteSkills}"; - text += "\n#BF9959"; - for (int i=0; i<6; ++i) - { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; - if (i<5) - text += ", "; - } - - text += "\n"; - - if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); - if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); - } - } - - w->setUserString("ToolTipType", "Layout"); - w->setUserString("ToolTipLayout", "TextToolTip"); - w->setUserString("Caption_Text", text); - } - } - - if (!mBirthSignId.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); - const ESM::BirthSign *sign = - store.get().find(mBirthSignId); - MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); - - ToolTips::createBirthsignToolTip(w, mBirthSignId); - } - - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); - } - - addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); - } - - mClientHeight = coord1.top; - - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::onPinToggled() -{ - mWindowManager.setHMSVisibility(!mPinned); -} diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp deleted file mode 100644 index 3befc1f002..0000000000 --- a/apps/openmw/mwgui/stats_window.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef MWGUI_STATS_WINDOW_H -#define MWGUI_STATS_WINDOW_H - -#include "../mwworld/esmstore.hpp" - -#include -#include -#include -#include - -#include "../mwmechanics/stat.hpp" -#include "window_pinnable_base.hpp" - -namespace MWGui -{ - class WindowManager; - - class StatsWindow : public WindowPinnableBase - { - public: - typedef std::map FactionList; - - typedef std::vector SkillList; - - StatsWindow(MWBase::WindowManager& parWindowManager); - - /// automatically updates all the data in the stats window, but only if it has changed. - void onFrame(); - - void setBar(const std::string& name, const std::string& tname, int val, int max); - void setPlayerName(const std::string& playerName); - - /// Set value for the given ID. - void setValue (const std::string& id, const MWMechanics::Stat& value); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setValue (const std::string& id, const std::string& value); - void setValue (const std::string& id, int value); - void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); - - void configureSkills (const SkillList& major, const SkillList& minor); - void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } - void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } - void updateSkillArea(); - - private: - void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - - void setFactions (const FactionList& factions); - void setExpelled (const std::set& expelled); - void setBirthSign (const std::string &signId); - - void onWindowResize(MyGUI::Window* window); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); - - static const int sLineHeight; - - MyGUI::Widget* mLeftPane; - MyGUI::Widget* mRightPane; - - MyGUI::ScrollView* mSkillView; - int mLastPos, mClientHeight; - - SkillList mMajorSkills, mMinorSkills, mMiscSkills; - std::map > mSkillValues; - std::map mSkillWidgetMap; - std::map mFactionWidgetMap; - FactionList mFactions; ///< Stores a list of factions and the current rank - std::string mBirthSignId; - int mReputation, mBounty; - std::vector mSkillWidgets; //< Skills and other information - std::set mExpelled; - - bool mChanged; - - protected: - virtual void onPinToggled(); - }; -} -#endif diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp deleted file mode 100644 index ee9144be68..0000000000 --- a/apps/openmw/mwgui/text_input.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "text_input.hpp" - -#include "../mwbase/windowmanager.hpp" - -using namespace MWGui; - -TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_text_input.layout", parWindowManager) -{ - // Centre dialog - center(); - - getWidget(mTextEdit, "TextEdit"); - mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -void TextInputDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); - else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); -} - -void TextInputDialog::setTextLabel(const std::string &label) -{ - setText("LabelT", label); -} - -void TextInputDialog::open() -{ - WindowModal::open(); - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -// widget controls - -void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if (mTextEdit->getCaption() == "") - { - mWindowManager.messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} - -void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) -{ - if (mTextEdit->getCaption() == "") - { - mWindowManager.messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp deleted file mode 100644 index 29de7388b2..0000000000 --- a/apps/openmw/mwgui/text_input.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MWGUI_TEXT_INPUT_H -#define MWGUI_TEXT_INPUT_H - -#include "window_base.hpp" - -namespace MWGui -{ - class WindowManager; -} - -/* - */ - -namespace MWGui -{ - class TextInputDialog : public WindowModal - { - public: - TextInputDialog(MWBase::WindowManager& parWindowManager); - - std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } - void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } - - void setNextButtonShow(bool shown); - void setTextLabel(const std::string &label); - virtual void open(); - - protected: - void onOkClicked(MyGUI::Widget* _sender); - void onTextAccepted(MyGUI::Edit* _sender); - - private: - MyGUI::EditBox* mTextEdit; - }; -} -#endif diff --git a/apps/openmw/mwgui/window_base.cpp b/apps/openmw/mwgui/window_base.cpp deleted file mode 100644 index 38bee9ea30..0000000000 --- a/apps/openmw/mwgui/window_base.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "window_base.hpp" - -#include - -#include "../mwbase/windowmanager.hpp" - -using namespace MWGui; - -WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : Layout(parLayout) - , mWindowManager(parWindowManager) -{ -} - -void WindowBase::setVisible(bool visible) -{ - bool wasVisible = mMainWidget->getVisible(); - mMainWidget->setVisible(visible); - - if (visible) - open(); - else if (wasVisible && !visible) - close(); -} - -void WindowBase::center() -{ - // Centre dialog - - // MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - // Note by scrawl: The following works more reliably in the case when the window was _just_ - // resized and MyGUI RenderManager doesn't know about the new size yet - MyGUI::IntSize gameWindowSize = MyGUI::IntSize(Settings::Manager::getInt("resolution x", "Video"), - Settings::Manager::getInt("resolution y", "Video")); - - MyGUI::IntCoord coord = mMainWidget->getCoord(); - coord.left = (gameWindowSize.width - coord.width)/2; - coord.top = (gameWindowSize.height - coord.height)/2; - mMainWidget->setCoord(coord); -} - -WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager) -{ -} - -void WindowModal::open() -{ - MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); -} - -void WindowModal::close() -{ - MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); -} diff --git a/apps/openmw/mwgui/window_base.hpp b/apps/openmw/mwgui/window_base.hpp deleted file mode 100644 index afdf4d065b..0000000000 --- a/apps/openmw/mwgui/window_base.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef MWGUI_WINDOW_BASE_H -#define MWGUI_WINDOW_BASE_H - -#include - -namespace MWBase -{ - class WindowManager; -} - -namespace MWGui -{ - class WindowManager; - - class WindowBase: public OEngine::GUI::Layout - { - public: - WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - - // Events - typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; - - virtual void open() {} - virtual void close () {} - virtual void setVisible(bool visible); - void center(); - - /** Event : Dialog finished, OK button clicked.\n - signature : void method()\n - */ - EventHandle_WindowBase eventDone; - - protected: - /// \todo remove - MWBase::WindowManager& mWindowManager; - }; - - - /* - * "Modal" windows cause the rest of the interface to be unaccessible while they are visible - */ - class WindowModal : public WindowBase - { - public: - WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - virtual void open(); - virtual void close(); - }; -} - -#endif diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp deleted file mode 100644 index 651b3a1e98..0000000000 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "window_pinnable_base.hpp" - -#include "../mwbase/windowmanager.hpp" - -#include "exposedwindow.hpp" - -using namespace MWGui; - -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) -{ - ExposedWindow* window = static_cast(mMainWidget); - mPinButton = window->getSkinWidget ("Button"); - - mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); -} - -void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) -{ - mPinned = !mPinned; - - if (mPinned) - mPinButton->changeWidgetSkin ("PinDown"); - else - mPinButton->changeWidgetSkin ("PinUp"); - - onPinToggled(); -} diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp deleted file mode 100644 index 50259858e2..0000000000 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MWGUI_WINDOW_PINNABLE_BASE_H -#define MWGUI_WINDOW_PINNABLE_BASE_H - -#include "window_base.hpp" - -namespace MWGui -{ - class WindowManager; - - class WindowPinnableBase: public WindowBase - { - public: - WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - bool pinned() { return mPinned; } - - private: - void onPinButtonClicked(MyGUI::Widget* _sender); - - protected: - virtual void onPinToggled() = 0; - - MyGUI::Widget* mPinButton; - bool mPinned; - bool mVisible; - }; -} - -#endif From d61ec1063e7c008ea2a1b6a1d90b60d94de85624 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 20:14:10 +0200 Subject: [PATCH 1034/1483] added script editor --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 25 +++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/view/world/scriptsubview.cpp | 92 ++++++++++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 62 ++++++++++++++++ apps/opencs/view/world/subviews.cpp | 2 + 7 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/world/scriptsubview.cpp create mode 100644 apps/opencs/view/world/scriptsubview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 76d4280c8f..bd882892fd 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -55,7 +55,7 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world - table tablesubview + table tablesubview scriptsubview ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 23049164f8..fea618037c 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -35,7 +35,8 @@ namespace CSMWorld Display_Specialisation, Display_Attribute, Display_Boolean, - Display_SpellType + Display_SpellType, + Display_Script }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6d6d1b1ef0..9242e8a23b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -723,6 +723,31 @@ namespace CSMWorld return true; } }; + + template + struct ScriptColumn : public Column + { + ScriptColumn() : Column ("Script", ColumnBase::Display_Script, 0) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mScriptText.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mScriptText = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 14aff47e89..9f6b186c0c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -93,6 +93,7 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); mScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Script)); + mScripts.addColumn (new ScriptColumn); mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp new file mode 100644 index 0000000000..2fdb44aec3 --- /dev/null +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -0,0 +1,92 @@ + +#include "scriptsubview.hpp" + +#include + +#include + +#include "../../model/doc/document.hpp" +#include "../../model/world/universalid.hpp" +#include "../../model/world/data.hpp" +#include "../../model/world/columnbase.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" + +CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) +{ + ++mView.mChangeLocked; +} + +CSVWorld::ScriptSubView::ChangeLock::~ChangeLock() +{ + --mView.mChangeLocked; +} + +CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0) +{ + setWidget (mEditor = new QTextEdit (this)); + + mEditor->setAcceptRichText (false); + mEditor->setLineWrapMode (QTextEdit::NoWrap); + mEditor->setTabStopWidth (4); + mEditor->setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead + + mModel = &dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); + + for (int i=0; icolumnCount(); ++i) + if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== + CSMWorld::ColumnBase::Display_Script) + { + mColumn = i; + break; + } + + if (mColumn==-1) + throw std::logic_error ("Can't find script column"); + + mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + + connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); + + connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); + +// connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int start, int end)), +// this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int start, int end))); +} + +void CSVWorld::ScriptSubView::setEditLock (bool locked) +{ + mEditor->setReadOnly (locked); +} + +void CSVWorld::ScriptSubView::textChanged() +{ + ChangeLock lock (*this); + + mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, + mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText())); +} + +void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + if (mChangeLocked) + return; + + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + + if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && + index.column()>=topLeft.column() && index.column()<=bottomRight.column()) + { + QTextCursor cursor = mEditor->textCursor(); + mEditor->setPlainText (mModel->data (index).toString()); + mEditor->setTextCursor (cursor); + } +} + +void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + +} \ No newline at end of file diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp new file mode 100644 index 0000000000..07d87d9476 --- /dev/null +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -0,0 +1,62 @@ +#ifndef CSV_WORLD_SCRIPTSUBVIEW_H +#define CSV_WORLD_SCRIPTSUBVIEW_H + +#include "../doc/subview.hpp" + +class QTextEdit; +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class IdTable; +} + +namespace CSVWorld +{ + class ScriptSubView : public CSVDoc::SubView + { + Q_OBJECT + + QTextEdit *mEditor; + CSMDoc::Document& mDocument; + CSMWorld::IdTable *mModel; + int mColumn; + int mChangeLocked; + + class ChangeLock + { + ScriptSubView& mView; + + ChangeLock (const ChangeLock&); + ChangeLock& operator= (const ChangeLock&); + + public: + + ChangeLock (ScriptSubView& view); + ~ChangeLock(); + }; + + friend class ChangeLock; + + public: + + ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + private slots: + + void textChanged(); + + void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index c9ef4df8db..8f7887f3b9 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -5,6 +5,7 @@ #include "tablesubview.hpp" #include "dialoguesubview.hpp" +#include "scriptsubview.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -32,6 +33,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) for (int i=0; sTableTypes[i]!=CSMWorld::UniversalId::Type_None; ++i) manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory); // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); From f7383905b7ca21a6aae6dd438ce0cc948eedf2be Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 14:46:21 -0400 Subject: [PATCH 1035/1483] Finally eliminated calls to MWBase::WindowManager in constructors --- apps/openmw/mwgui/alchemywindow.cpp | 4 +- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/birth.cpp | 4 +- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 4 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.cpp | 197 +++++++++++----------- apps/openmw/mwgui/charactercreation.hpp | 4 +- apps/openmw/mwgui/class.cpp | 44 ++--- apps/openmw/mwgui/class.hpp | 18 +- apps/openmw/mwgui/companionwindow.cpp | 4 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.cpp | 4 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/container.cpp | 4 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.cpp | 4 +- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 10 +- apps/openmw/mwgui/dialogue.hpp | 4 +- apps/openmw/mwgui/enchantingdialog.cpp | 10 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 4 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/itemselection.cpp | 4 +- apps/openmw/mwgui/itemselection.hpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 +- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/levelupdialog.cpp | 4 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 4 +- apps/openmw/mwgui/loadingscreen.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 4 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/merchantrepair.cpp | 4 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 4 +- apps/openmw/mwgui/messagebox.hpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 18 +- apps/openmw/mwgui/quickkeysmenu.hpp | 6 +- apps/openmw/mwgui/race.cpp | 4 +- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 4 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 4 +- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 4 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 4 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 18 +- apps/openmw/mwgui/spellcreationdialog.hpp | 6 +- apps/openmw/mwgui/spellwindow.cpp | 4 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 4 +- apps/openmw/mwgui/statswindow.hpp | 2 +- apps/openmw/mwgui/textinput.cpp | 4 +- apps/openmw/mwgui/textinput.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 4 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 4 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 4 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 10 +- apps/openmw/mwgui/waitdialog.hpp | 4 +- apps/openmw/mwgui/widgets.cpp | 14 +- apps/openmw/mwgui/widgets.hpp | 4 - apps/openmw/mwgui/windowbase.cpp | 6 +- apps/openmw/mwgui/windowbase.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 58 +++---- apps/openmw/mwgui/windowpinnablebase.cpp | 4 +- apps/openmw/mwgui/windowpinnablebase.hpp | 2 +- 77 files changed, 300 insertions(+), 309 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 1ae534797d..a6121c234c 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -26,8 +26,8 @@ namespace namespace MWGui { - AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_alchemy_window.layout", parWindowManager) + AlchemyWindow::AlchemyWindow() + : WindowBase("openmw_alchemy_window.layout") , ContainerBase(0), mApparatus (4), mIngredients (4) { getWidget(mCreateButton, "CreateButton"); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 933975f0c8..c61d2f92b3 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -14,7 +14,7 @@ namespace MWGui class AlchemyWindow : public WindowBase, public ContainerBase { public: - AlchemyWindow(MWBase::WindowManager& parWindowManager); + AlchemyWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index d899ab00b1..133bbd32fb 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -24,8 +24,8 @@ bool sortBirthSigns(const std::pair& left, c } -BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_birth.layout", parWindowManager) +BirthDialog::BirthDialog() + : WindowModal("openmw_chargen_birth.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 033501f22f..cc958ddcaa 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -13,7 +13,7 @@ namespace MWGui class BirthDialog : public WindowModal { public: - BirthDialog(MWBase::WindowManager& parWindowManager); + BirthDialog(); enum Gender { diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index d57953d07d..ce74c48593 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -14,8 +14,8 @@ using namespace MWGui; -BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_book.layout", parWindowManager) +BookWindow::BookWindow () + : WindowBase("openmw_book.layout") , mTakeButtonShow(true) , mTakeButtonAllowed(true) { diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index c2a9dca893..9123969e09 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -12,7 +12,7 @@ namespace MWGui class BookWindow : public WindowBase { public: - BookWindow(MWBase::WindowManager& parWindowManager); + BookWindow(); void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 27de7cee98..0dd6502c6c 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -47,7 +47,7 @@ namespace using namespace MWGui; -CharacterCreation::CharacterCreation(MWBase::WindowManager* _wm) +CharacterCreation::CharacterCreation() : mNameDialog(0) , mRaceDialog(0) , mClassChoiceDialog(0) @@ -58,7 +58,6 @@ CharacterCreation::CharacterCreation(MWBase::WindowManager* _wm) , mBirthSignDialog(0) , mReviewDialog(0) , mGenerateClassStep(0) - , mWM(_wm) { mCreationStage = CSE_NotStarted; } @@ -118,10 +117,10 @@ void CharacterCreation::spawnDialog(const char id) switch (id) { case GM_Name: - mWM->removeDialog(mNameDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = 0; - mNameDialog = new TextInputDialog(*mWM); - mNameDialog->setTextLabel(mWM->getGameSettingString("sName", "Name")); + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); mNameDialog->setTextInput(mPlayerName); mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); @@ -129,9 +128,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Race: - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; - mRaceDialog = new RaceDialog(*mWM); + mRaceDialog = new RaceDialog(); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); @@ -142,9 +141,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Class: - mWM->removeDialog(mClassChoiceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(*mWM); + mClassChoiceDialog = new ClassChoiceDialog(); mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); mClassChoiceDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) @@ -152,9 +151,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_ClassPick: - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(*mWM); + mPickClassDialog = new PickClassDialog(); mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mPickClassDialog->setClassId(mPlayerClass.mName); mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); @@ -165,9 +164,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Birth: - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(*mWM); + mBirthSignDialog = new BirthDialog(); mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); mBirthSignDialog->setBirthId(mPlayerBirthSignId); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); @@ -178,9 +177,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_ClassCreate: - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mCreateClassDialog = new CreateClassDialog(*mWM); + mCreateClassDialog = new CreateClassDialog(); mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); @@ -199,9 +198,9 @@ void CharacterCreation::spawnDialog(const char id) mCreationStage = CSE_RaceChosen; break; case GM_Review: - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mReviewDialog = new ReviewDialog(*mWM); + mReviewDialog = new ReviewDialog(); mReviewDialog->setPlayerName(mPlayerName); mReviewDialog->setRace(mPlayerRaceId); mReviewDialog->setClass(mPlayerClass); @@ -212,7 +211,7 @@ void CharacterCreation::spawnDialog(const char id) mReviewDialog->setFatigue(mPlayerFatigue); { - std::map > attributes = mWM->getPlayerAttributeValues(); + std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); for (std::map >::iterator it = attributes.begin(); it != attributes.end(); ++it) { @@ -221,13 +220,13 @@ void CharacterCreation::spawnDialog(const char id) } { - std::map > skills = mWM->getPlayerSkillValues(); + std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); for (std::map >::iterator it = skills.begin(); it != skills.end(); ++it) { mReviewDialog->setSkillValue(static_cast (it->first), it->second); } - mReviewDialog->configureSkills(mWM->getPlayerMajorSkills(), mWM->getPlayerMinorSkills()); + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); } mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); @@ -257,41 +256,41 @@ void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } void CharacterCreation::onReviewDialogBack() { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } void CharacterCreation::onReviewActivateDialog(int parDialog) { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; mCreationStage = CSE_ReviewNext; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); switch(parDialog) { case ReviewDialog::NAME_DIALOG: - mWM->pushGuiMode(GM_Name); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); break; case ReviewDialog::RACE_DIALOG: - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); break; case ReviewDialog::CLASS_DIALOG: - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); break; case ReviewDialog::BIRTHSIGN_DIALOG: - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); }; } @@ -308,27 +307,27 @@ void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) if (klass) { mPlayerClass = *klass; - mWM->setPlayerClass(mPlayerClass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); } - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; } //TODO This bit gets repeated a few times; wrap it in a function if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -339,34 +338,34 @@ void CharacterCreation::onPickClassDialogBack() const std::string classId = mPickClassDialog->getClassId(); if (!classId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onClassChoice(int _index) { - mWM->removeDialog(mClassChoiceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = 0; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); switch(_index) { case ClassChoiceDialog::Class_Generate: - mWM->pushGuiMode(GM_ClassGenerate); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); break; case ClassChoiceDialog::Class_Pick: - mWM->pushGuiMode(GM_ClassPick); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); break; case ClassChoiceDialog::Class_Create: - mWM->pushGuiMode(GM_ClassCreate); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); break; case ClassChoiceDialog::Class_Back: - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); break; }; @@ -377,26 +376,26 @@ void CharacterCreation::onNameDialogDone(WindowBase* parWindow) if (mNameDialog) { mPlayerName = mNameDialog->getTextInput(); - mWM->setValue("name", mPlayerName); + MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); - mWM->removeDialog(mNameDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_NameChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); } else { mCreationStage = CSE_NameChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -414,12 +413,12 @@ void CharacterCreation::onRaceDialogBack() data.mHair ); } - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Name); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); } void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) @@ -436,26 +435,26 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) data.mHair ); } - mWM->getInventoryWindow()->rebuildAvatar(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_RaceChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } else { mCreationStage = CSE_RaceChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -466,19 +465,19 @@ void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) mPlayerBirthSignId = mBirthSignDialog->getBirthId(); if (!mPlayerBirthSignId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; } if (mCreationStage >= CSE_BirthSignChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else { mCreationStage = CSE_BirthSignChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -487,12 +486,12 @@ void CharacterCreation::onBirthSignDialogBack() if (mBirthSignDialog) { MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) @@ -522,49 +521,49 @@ void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); mPlayerClass = klass; - mWM->setPlayerClass(klass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } void CharacterCreation::onCreateClassDialogBack() { - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onClassQuestionChosen(int _index) { MWBase::Environment::get().getSoundManager()->stopSay(); - mWM->removeDialog(mGenerateClassQuestionDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); mGenerateClassQuestionDialog = 0; if (_index < 0 || _index >= 3) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); return; } @@ -637,10 +636,10 @@ void CharacterCreation::showClassQuestionDialog() } } - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; - mGenerateClassResultDialog = new GenerateClassResultDialog(*mWM); + mGenerateClassResultDialog = new GenerateClassResultDialog(); mGenerateClassResultDialog->setClassId(mGenerateClass); mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); @@ -650,15 +649,15 @@ void CharacterCreation::showClassQuestionDialog() if (mGenerateClassStep > 10) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); return; } - mWM->removeDialog(mGenerateClassQuestionDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); mGenerateClassQuestionDialog = 0; - mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM); + mGenerateClassQuestionDialog = new InfoBoxDialog(); InfoBoxDialog::ButtonList buttons; mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); @@ -674,18 +673,18 @@ void CharacterCreation::showClassQuestionDialog() void CharacterCreation::onGenerateClassBack() { - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); @@ -694,22 +693,22 @@ void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); mPlayerClass = *klass; - mWM->setPlayerClass(mPlayerClass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 9653aeede5..fed77e889f 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -29,7 +29,7 @@ namespace MWGui public: typedef std::vector SkillList; - CharacterCreation(MWBase::WindowManager* _wm); + CharacterCreation(); ~CharacterCreation(); //Show a dialog @@ -58,8 +58,6 @@ namespace MWGui BirthDialog* mBirthSignDialog; ReviewDialog* mReviewDialog; - MWBase::WindowManager* mWM; - //Player data std::string mPlayerName; std::string mPlayerRaceId; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 8c352d5080..6edad9e83b 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -20,8 +20,8 @@ using namespace MWGui; /* GenerateClassResultDialog */ -GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_generate_class_result.layout", parWindowManager) +GenerateClassResultDialog::GenerateClassResultDialog() + : WindowModal("openmw_chargen_generate_class_result.layout") { // Centre dialog center(); @@ -67,8 +67,8 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) /* PickClassDialog */ -PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_class.layout", parWindowManager) +PickClassDialog::PickClassDialog() + : WindowModal("openmw_chargen_class.layout") { // Centre dialog center(); @@ -272,8 +272,8 @@ void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) widget->setSize(width, pos); } -InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_infobox.layout", parWindowManager) +InfoBoxDialog::InfoBoxDialog() + : WindowModal("openmw_infobox.layout") , mCurrentButton(-1) { getWidget(mTextBox, "TextBox"); @@ -356,8 +356,8 @@ void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) /* ClassChoiceDialog */ -ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) - : InfoBoxDialog(parWindowManager) +ClassChoiceDialog::ClassChoiceDialog() + : InfoBoxDialog() { setText(""); ButtonList buttons; @@ -370,8 +370,8 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) /* CreateClassDialog */ -CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_create_class.layout", parWindowManager) +CreateClassDialog::CreateClassDialog() + : WindowModal("openmw_chargen_create_class.layout") , mSpecDialog(NULL) , mAttribDialog(NULL) , mSkillDialog(NULL) @@ -540,7 +540,7 @@ void CreateClassDialog::onDialogCancel() void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) { delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(*MWBase::Environment::get().getWindowManager()); + mSpecDialog = new SelectSpecializationDialog(); mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); mSpecDialog->setVisible(true); @@ -571,7 +571,7 @@ void CreateClassDialog::setSpecialization(int id) void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager()); + mAttribDialog = new SelectAttributeDialog(); mAffectedAttribute = _sender; mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); @@ -601,7 +601,7 @@ void CreateClassDialog::onAttributeSelected() void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager()); + mSkillDialog = new SelectSkillDialog(); mAffectedSkill = _sender; mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); @@ -633,7 +633,7 @@ void CreateClassDialog::onSkillSelected() void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) { - mDescDialog = new DescriptionDialog(*MWBase::Environment::get().getWindowManager()); + mDescDialog = new DescriptionDialog(); mDescDialog->setTextInput(mDescription); mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); mDescDialog->setVisible(true); @@ -660,8 +660,8 @@ void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) /* SelectSpecializationDialog */ -SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_specialization.layout", parWindowManager) +SelectSpecializationDialog::SelectSpecializationDialog() + : WindowModal("openmw_chargen_select_specialization.layout") { // Centre dialog center(); @@ -720,8 +720,8 @@ void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) /* SelectAttributeDialog */ -SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_attribute.layout", parWindowManager) +SelectAttributeDialog::SelectAttributeDialog() + : WindowModal("openmw_chargen_select_attribute.layout") { // Centre dialog center(); @@ -766,8 +766,8 @@ void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) /* SelectSkillDialog */ -SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_skill.layout", parWindowManager) +SelectSkillDialog::SelectSkillDialog() + : WindowModal("openmw_chargen_select_skill.layout") { // Centre dialog center(); @@ -856,8 +856,8 @@ void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) /* DescriptionDialog */ -DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_class_description.layout", parWindowManager) +DescriptionDialog::DescriptionDialog() + : WindowModal("openmw_chargen_class_description.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 11da1a7913..15fc89658f 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -15,7 +15,7 @@ namespace MWGui class InfoBoxDialog : public WindowModal { public: - InfoBoxDialog(MWBase::WindowManager& parWindowManager); + InfoBoxDialog(); typedef std::vector ButtonList; @@ -60,13 +60,13 @@ namespace MWGui Class_Create = 2, Class_Back = 3 }; - ClassChoiceDialog(MWBase::WindowManager& parWindowManager); + ClassChoiceDialog(); }; class GenerateClassResultDialog : public WindowModal { public: - GenerateClassResultDialog(MWBase::WindowManager& parWindowManager); + GenerateClassResultDialog(); std::string getClassId() const; void setClassId(const std::string &classId); @@ -93,7 +93,7 @@ namespace MWGui class PickClassDialog : public WindowModal { public: - PickClassDialog(MWBase::WindowManager& parWindowManager); + PickClassDialog(); const std::string &getClassId() const { return mCurrentClassId; } void setClassId(const std::string &classId); @@ -132,7 +132,7 @@ namespace MWGui class SelectSpecializationDialog : public WindowModal { public: - SelectSpecializationDialog(MWBase::WindowManager& parWindowManager); + SelectSpecializationDialog(); ~SelectSpecializationDialog(); ESM::Class::Specialization getSpecializationId() const { return mSpecializationId; } @@ -163,7 +163,7 @@ namespace MWGui class SelectAttributeDialog : public WindowModal { public: - SelectAttributeDialog(MWBase::WindowManager& parWindowManager); + SelectAttributeDialog(); ~SelectAttributeDialog(); ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; } @@ -192,7 +192,7 @@ namespace MWGui class SelectSkillDialog : public WindowModal { public: - SelectSkillDialog(MWBase::WindowManager& parWindowManager); + SelectSkillDialog(); ~SelectSkillDialog(); ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } @@ -225,7 +225,7 @@ namespace MWGui class DescriptionDialog : public WindowModal { public: - DescriptionDialog(MWBase::WindowManager& parWindowManager); + DescriptionDialog(); ~DescriptionDialog(); std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } @@ -241,7 +241,7 @@ namespace MWGui class CreateClassDialog : public WindowModal { public: - CreateClassDialog(MWBase::WindowManager& parWindowManager); + CreateClassDialog(); virtual ~CreateClassDialog(); std::string getName() const; diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 643cdf4c65..0a20c471ab 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -13,9 +13,9 @@ namespace MWGui { -CompanionWindow::CompanionWindow(MWBase::WindowManager &parWindowManager, DragAndDrop *dragAndDrop, MessageBoxManager* manager) +CompanionWindow::CompanionWindow(DragAndDrop *dragAndDrop, MessageBoxManager* manager) : ContainerBase(dragAndDrop) - , WindowBase("openmw_companion_window.layout", parWindowManager) + , WindowBase("openmw_companion_window.layout") , mMessageBoxManager(manager) { MyGUI::ScrollView* itemView; diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 1b64a34d50..073a77a916 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -11,7 +11,7 @@ namespace MWGui class CompanionWindow : public ContainerBase, public WindowBase { public: - CompanionWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop, MessageBoxManager* manager); + CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); virtual ~CompanionWindow() {} void open(MWWorld::Ptr npc); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 31f4989e07..904468f886 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -7,8 +7,8 @@ namespace MWGui { - ConfirmationDialog::ConfirmationDialog(MWBase::WindowManager& parWindowManager) : - WindowModal("openmw_confirmation_dialog.layout", parWindowManager) + ConfirmationDialog::ConfirmationDialog() : + WindowModal("openmw_confirmation_dialog.layout") { getWidget(mMessage, "Message"); getWidget(mOkButton, "OkButton"); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index a925cad550..47b256017f 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -8,7 +8,7 @@ namespace MWGui class ConfirmationDialog : public WindowModal { public: - ConfirmationDialog(MWBase::WindowManager& parWindowManager); + ConfirmationDialog(); void open(const std::string& message); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index f7846e70ec..8ee4754a32 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -649,9 +649,9 @@ MWWorld::ContainerStore& ContainerBase::getContainerStore() // ------------------------------------------------------------------------------------------------ -ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop) +ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) - , WindowBase("openmw_container_window.layout", parWindowManager) + , WindowBase("openmw_container_window.layout") { getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mTakeButton, "TakeButton"); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 7a3e804e5d..521ac8cc35 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -134,7 +134,7 @@ namespace MWGui class ContainerWindow : public ContainerBase, public WindowBase { public: - ContainerWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + ContainerWindow(DragAndDrop* dragAndDrop); virtual ~ContainerWindow(); diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 61c3c358a2..d017cc1986 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -7,8 +7,8 @@ namespace MWGui { - CountDialog::CountDialog(MWBase::WindowManager& parWindowManager) : - WindowModal("openmw_count_window.layout", parWindowManager) + CountDialog::CountDialog() : + WindowModal("openmw_count_window.layout") { getWidget(mSlider, "CountSlider"); getWidget(mItemEdit, "ItemEdit"); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index d5155839d8..9d6d8b263f 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -8,7 +8,7 @@ namespace MWGui class CountDialog : public WindowModal { public: - CountDialog(MWBase::WindowManager& parWindowManager); + CountDialog(); void open(const std::string& item, const std::string& message, const int maxCount); typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0939da1b17..f3c11752e8 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -55,8 +55,8 @@ bool sortByLength (const std::string& left, const std::string& right) -PersuasionDialog::PersuasionDialog(MWBase::WindowManager &parWindowManager) - : WindowModal("openmw_persuasion_dialog.layout", parWindowManager) +PersuasionDialog::PersuasionDialog() + : WindowModal("openmw_persuasion_dialog.layout") { getWidget(mCancelButton, "CancelButton"); getWidget(mAdmireButton, "AdmireButton"); @@ -124,9 +124,9 @@ void PersuasionDialog::open() // -------------------------------------------------------------------------------------------------- -DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_dialogue_window.layout", parWindowManager) - , mPersuasionDialog(parWindowManager) +DialogueWindow::DialogueWindow() + : WindowBase("openmw_dialogue_window.layout") + , mPersuasionDialog() , mEnabled(false) , mServices(0) { diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index e78856c951..a1bbee02c7 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -29,7 +29,7 @@ namespace MWGui class PersuasionDialog : public WindowModal { public: - PersuasionDialog(MWBase::WindowManager& parWindowManager); + PersuasionDialog(); virtual void open(); @@ -50,7 +50,7 @@ namespace MWGui class DialogueWindow: public WindowBase, public ReferenceInterface { public: - DialogueWindow(MWBase::WindowManager& parWindowManager); + DialogueWindow(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 02d847d1a8..2ae98f358f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -15,9 +15,9 @@ namespace MWGui { - EnchantingDialog::EnchantingDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) - , EffectEditorBase(parWindowManager) + EnchantingDialog::EnchantingDialog() + : WindowBase("openmw_enchanting_dialog.layout") + , EffectEditorBase() , mItemSelectionDialog(NULL) { getWidget(mName, "NameEdit"); @@ -139,7 +139,7 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}", - ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, *MWBase::Environment::get().getWindowManager()); + ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); @@ -227,7 +227,7 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}", - ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, *MWBase::Environment::get().getWindowManager()); + ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 822199ac67..c727a09749 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -17,7 +17,7 @@ namespace MWGui class EnchantingDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { public: - EnchantingDialog(MWBase::WindowManager& parWindowManager); + EnchantingDialog(); virtual ~EnchantingDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 393f03a541..dc7ef77ff8 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -30,9 +30,9 @@ namespace MWGui { - InventoryWindow::InventoryWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop) + InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) - , WindowPinnableBase("openmw_inventory_window.layout", parWindowManager) + , WindowPinnableBase("openmw_inventory_window.layout") , mTrading(false) , mLastXSize(0) , mLastYSize(0) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 61ee17ef93..a4ed89d401 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -12,7 +12,7 @@ namespace MWGui class InventoryWindow : public ContainerBase, public WindowPinnableBase { public: - InventoryWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + InventoryWindow(DragAndDrop* dragAndDrop); virtual void open(); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 4b8adcef4f..ed8b47b086 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -3,9 +3,9 @@ namespace MWGui { - ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter, MWBase::WindowManager& parWindowManager) + ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter) : ContainerBase(NULL) - , WindowModal("openmw_itemselection_dialog.layout", parWindowManager) + , WindowModal("openmw_itemselection_dialog.layout") { mFilter = filter; diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 733daa91ae..3e812d26c5 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -8,7 +8,7 @@ namespace MWGui class ItemSelectionDialog : public ContainerBase, public WindowModal { public: - ItemSelectionDialog(const std::string& label, int filter, MWBase::WindowManager& parWindowManager); + ItemSelectionDialog(const std::string& label, int filter); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index ba39b01012..a3198d6bcd 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -81,8 +81,8 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) } -MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_journal.layout", parWindowManager) +MWGui::JournalWindow::JournalWindow () + : WindowBase("openmw_journal.layout") , mPageNumber(0) { mMainWidget->setVisible(false); diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 73a2dca2ec..7670b65f55 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -14,7 +14,7 @@ namespace MWGui class JournalWindow : public WindowBase { public: - JournalWindow(MWBase::WindowManager& parWindowManager); + JournalWindow(); virtual void open(); virtual void close(); diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index dcecdccc1b..fc1317e908 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -18,8 +18,8 @@ namespace MWGui { - LevelupDialog::LevelupDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_levelup_dialog.layout", parWindowManager) + LevelupDialog::LevelupDialog() + : WindowBase("openmw_levelup_dialog.layout") { getWidget(mOkButton, "OkButton"); getWidget(mClassImage, "ClassImage"); diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index a54948e2a0..69afbf0897 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui class LevelupDialog : public WindowBase { public: - LevelupDialog(MWBase::WindowManager& parWindowManager); + LevelupDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 3066705124..858c3f36ec 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -23,10 +23,10 @@ namespace MWGui { - LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw, MWBase::WindowManager& parWindowManager) + LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw) : mSceneMgr(sceneMgr) , mWindow(rw) - , WindowBase("openmw_loading_screen.layout", parWindowManager) + , WindowBase("openmw_loading_screen.layout") , mLoadingOn(false) , mLastRenderTime(0.f) , mLastWallpaperChangeTime(0.f) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index cb33975ae3..12e6504bca 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -11,7 +11,7 @@ namespace MWGui class LoadingScreen : public WindowBase { public: - LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw, MWBase::WindowManager& parWindowManager); + LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw); virtual ~LoadingScreen(); void setLoadingProgress (const std::string& stage, int depth, int current, int total); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 029974d2b3..17834be937 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -262,8 +262,8 @@ void LocalMapBase::setPlayerDir(const float x, const float y) // ------------------------------------------------------------------------------------------ -MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) +MapWindow::MapWindow(const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout") , mGlobal(false) { setCoord(500,0,320,300); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 329854e182..18c81a0608 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -65,7 +65,7 @@ namespace MWGui class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase { public: - MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); + MapWindow(const std::string& cacheDir); virtual ~MapWindow(); void setCellName(const std::string& cellName); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index f24d2d4177..53148cb3f0 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -19,8 +19,8 @@ namespace MWGui { -MerchantRepair::MerchantRepair(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_merchantrepair.layout", parWindowManager) +MerchantRepair::MerchantRepair() + : WindowBase("openmw_merchantrepair.layout") { getWidget(mList, "RepairView"); getWidget(mOkButton, "OkButton"); diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 2cd6c486a9..4cb39fe012 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -12,7 +12,7 @@ namespace MWGui class MerchantRepair : public WindowBase { public: - MerchantRepair(MWBase::WindowManager &parWindowManager); + MerchantRepair(); virtual void open(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 58bbc3c3ab..8e53380bde 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -7,7 +7,7 @@ using namespace MWGui; -MessageBoxManager::MessageBoxManager (MWBase::WindowManager* windowManager) +MessageBoxManager::MessageBoxManager () { // defines mMessageBoxSpeed = 0.1; @@ -212,7 +212,7 @@ int MessageBox::getHeight () InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : WindowModal("openmw_interactive_messagebox.layout", *MWBase::Environment::get().getWindowManager()) + : WindowModal("openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index c64953b665..cb40739023 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -31,7 +31,7 @@ namespace MWGui class MessageBoxManager { public: - MessageBoxManager (MWBase::WindowManager* windowManager); + MessageBoxManager (); void onFrame (float frameDuration); void createMessageBox (const std::string& message); bool createInteractiveMessageBox (const std::string& message, const std::vector& buttons); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 82835a8058..2deb37d301 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -43,8 +43,8 @@ namespace namespace MWGui { - QuickKeysMenu::QuickKeysMenu(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_quickkeys_menu.layout", parWindowManager) + QuickKeysMenu::QuickKeysMenu() + : WindowBase("openmw_quickkeys_menu.layout") , mAssignDialog(0) , mItemSelectionDialog(0) , mMagicSelectionDialog(0) @@ -109,7 +109,7 @@ namespace MWGui { // open assign dialog if (!mAssignDialog) - mAssignDialog = new QuickKeysMenuAssign(*MWBase::Environment::get().getWindowManager(), this); + mAssignDialog = new QuickKeysMenuAssign(this); mAssignDialog->setVisible (true); } } @@ -124,7 +124,7 @@ namespace MWGui { if (!mItemSelectionDialog ) { - mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, *MWBase::Environment::get().getWindowManager()); + mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItem); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } @@ -139,7 +139,7 @@ namespace MWGui { if (!mMagicSelectionDialog ) { - mMagicSelectionDialog = new MagicSelectionDialog(*MWBase::Environment::get().getWindowManager(), this); + mMagicSelectionDialog = new MagicSelectionDialog(this); } mMagicSelectionDialog->setVisible(true); @@ -352,8 +352,8 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - QuickKeysMenuAssign::QuickKeysMenuAssign (MWBase::WindowManager &parWindowManager, QuickKeysMenu* parent) - : WindowModal("openmw_quickkeys_menu_assign.layout", parWindowManager) + QuickKeysMenuAssign::QuickKeysMenuAssign (QuickKeysMenu* parent) + : WindowModal("openmw_quickkeys_menu_assign.layout") , mParent(parent) { getWidget(mLabel, "Label"); @@ -399,8 +399,8 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - MagicSelectionDialog::MagicSelectionDialog(MWBase::WindowManager &parWindowManager, QuickKeysMenu* parent) - : WindowModal("openmw_magicselection_dialog.layout", parWindowManager) + MagicSelectionDialog::MagicSelectionDialog(QuickKeysMenu* parent) + : WindowModal("openmw_magicselection_dialog.layout") , mParent(parent) , mWidth(0) , mHeight(0) diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index d5b6e6cd85..646ec2aa45 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -16,7 +16,7 @@ namespace MWGui class QuickKeysMenu : public WindowBase { public: - QuickKeysMenu(MWBase::WindowManager& parWindowManager); + QuickKeysMenu(); ~QuickKeysMenu(); @@ -64,7 +64,7 @@ namespace MWGui class QuickKeysMenuAssign : public WindowModal { public: - QuickKeysMenuAssign(MWBase::WindowManager& parWindowManager, QuickKeysMenu* parent); + QuickKeysMenuAssign(QuickKeysMenu* parent); private: MyGUI::TextBox* mLabel; @@ -79,7 +79,7 @@ namespace MWGui class MagicSelectionDialog : public WindowModal { public: - MagicSelectionDialog(MWBase::WindowManager& parWindowManager, QuickKeysMenu* parent); + MagicSelectionDialog(QuickKeysMenu* parent); virtual void open(); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 167ad573a0..9a0d8a029f 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -62,8 +62,8 @@ int countParts(const std::string &part, const std::string &race, bool male) } } -RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_race.layout", parWindowManager) +RaceDialog::RaceDialog() + : WindowModal("openmw_chargen_race.layout") , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 4a4acd0112..f3adce4447 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -26,7 +26,7 @@ namespace MWGui class RaceDialog : public WindowModal { public: - RaceDialog(MWBase::WindowManager& parWindowManager); + RaceDialog(); enum Gender { diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 43c262ad85..0bd4b0995f 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -15,8 +15,8 @@ namespace MWGui { -Repair::Repair(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_repair.layout", parWindowManager) +Repair::Repair() + : WindowBase("openmw_repair.layout") { getWidget(mRepairBox, "RepairBox"); getWidget(mRepairView, "RepairView"); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 824e0b6d2a..5d9a487199 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -12,7 +12,7 @@ namespace MWGui class Repair : public WindowBase { public: - Repair(MWBase::WindowManager &parWindowManager); + Repair(); virtual void open(); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 74b1893456..562bf97748 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -22,8 +22,8 @@ using namespace Widgets; const int ReviewDialog::sLineHeight = 18; -ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_review.layout", parWindowManager) +ReviewDialog::ReviewDialog() + : WindowModal("openmw_chargen_review.layout") , mLastPos(0) { // Centre dialog diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 9775a52de4..d5df94e285 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -28,7 +28,7 @@ namespace MWGui }; typedef std::vector SkillList; - ReviewDialog(MWBase::WindowManager& parWindowManager); + ReviewDialog(); void setPlayerName(const std::string &name); void setRace(const std::string &raceId); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 22884bfe6d..1935f7a9b6 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,8 +12,8 @@ using namespace MWGui; -ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_scroll.layout", parWindowManager) +ScrollWindow::ScrollWindow () + : WindowBase("openmw_scroll.layout") , mTakeButtonShow(true) , mTakeButtonAllowed(true) { diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 59b39cab38..5feaff7bf8 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -11,7 +11,7 @@ namespace MWGui class ScrollWindow : public WindowBase { public: - ScrollWindow (MWBase::WindowManager& parWindowManager); + ScrollWindow (); void open (MWWorld::Ptr scroll); void setTakeButtonShow(bool show); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index e21d4f5894..c3718c2607 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -93,8 +93,8 @@ namespace namespace MWGui { - SettingsWindow::SettingsWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_settings_window.layout", parWindowManager) + SettingsWindow::SettingsWindow() : + WindowBase("openmw_settings_window.layout") { getWidget(mOkButton, "OkButton"); getWidget(mSubtitlesButton, "SubtitlesButton"); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 292c1233de..6dcef2422e 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -13,7 +13,7 @@ namespace MWGui class SettingsWindow : public WindowBase { public: - SettingsWindow(MWBase::WindowManager& parWindowManager); + SettingsWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9aa8074a24..7d634df8d6 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -23,8 +23,8 @@ namespace MWGui { const int SpellBuyingWindow::sLineHeight = 18; - SpellBuyingWindow::SpellBuyingWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_spell_buying_window.layout", parWindowManager) + SpellBuyingWindow::SpellBuyingWindow() : + WindowBase("openmw_spell_buying_window.layout") , mCurrentY(0) , mLastPos(0) { diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 1418a9db52..f7ea54c89c 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -21,7 +21,7 @@ namespace MWGui class SpellBuyingWindow : public ReferenceInterface, public WindowBase { public: - SpellBuyingWindow(MWBase::WindowManager& parWindowManager); + SpellBuyingWindow(); void startSpellBuying(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6fef91457f..e1df9f9cd1 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -40,8 +40,8 @@ namespace namespace MWGui { - EditEffectDialog::EditEffectDialog(MWBase::WindowManager &parWindowManager) - : WindowModal("openmw_edit_effect.layout", parWindowManager) + EditEffectDialog::EditEffectDialog() + : WindowModal("openmw_edit_effect.layout") , mEditing(false) { getWidget(mCancelButton, "CancelButton"); @@ -274,9 +274,9 @@ namespace MWGui // ------------------------------------------------------------------------------------------------ - SpellCreationDialog::SpellCreationDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_spellcreation_dialog.layout", parWindowManager) - , EffectEditorBase(parWindowManager) + SpellCreationDialog::SpellCreationDialog() + : WindowBase("openmw_spellcreation_dialog.layout") + , EffectEditorBase() { getWidget(mNameEdit, "NameEdit"); getWidget(mMagickaCost, "MagickaCost"); @@ -412,8 +412,8 @@ namespace MWGui // ------------------------------------------------------------------------------------------------ - EffectEditorBase::EffectEditorBase(MWBase::WindowManager& parWindowManager) - : mAddEffectDialog(parWindowManager) + EffectEditorBase::EffectEditorBase() + : mAddEffectDialog() , mSelectAttributeDialog(NULL) , mSelectSkillDialog(NULL) { @@ -541,7 +541,7 @@ namespace MWGui if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) { delete mSelectSkillDialog; - mSelectSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager ()); + mSelectSkillDialog = new SelectSkillDialog(); mSelectSkillDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel); mSelectSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectSkill); mSelectSkillDialog->setVisible (true); @@ -549,7 +549,7 @@ namespace MWGui else if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) { delete mSelectAttributeDialog; - mSelectAttributeDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager ()); + mSelectAttributeDialog = new SelectAttributeDialog(); mSelectAttributeDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel); mSelectAttributeDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectAttribute); mSelectAttributeDialog->setVisible (true); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index facbdf5304..5ad306fbea 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -15,7 +15,7 @@ namespace MWGui class EditEffectDialog : public WindowModal { public: - EditEffectDialog(MWBase::WindowManager& parWindowManager); + EditEffectDialog(); virtual void open(); @@ -83,7 +83,7 @@ namespace MWGui class EffectEditorBase { public: - EffectEditorBase(MWBase::WindowManager& parWindowManager); + EffectEditorBase(); protected: @@ -123,7 +123,7 @@ namespace MWGui class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { public: - SpellCreationDialog(MWBase::WindowManager& parWindowManager); + SpellCreationDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 257fab89d4..d07f9ca542 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -47,8 +47,8 @@ namespace namespace MWGui { - SpellWindow::SpellWindow(MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_spell_window.layout", parWindowManager) + SpellWindow::SpellWindow() + : WindowPinnableBase("openmw_spell_window.layout") , mHeight(0) , mWidth(0) { diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index b0994c5901..521e73d767 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -10,7 +10,7 @@ namespace MWGui class SpellWindow : public WindowPinnableBase { public: - SpellWindow(MWBase::WindowManager& parWindowManager); + SpellWindow(); virtual ~SpellWindow(); void updateSpells(); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 0e0676c2fb..a00ec167da 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -22,8 +22,8 @@ using namespace MWGui; const int StatsWindow::sLineHeight = 18; -StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) +StatsWindow::StatsWindow () + : WindowPinnableBase("openmw_stats_window.layout") , mSkillView(NULL) , mClientHeight(0) , mMajorSkills() diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 93e26e063d..4b723048cc 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -22,7 +22,7 @@ namespace MWGui typedef std::vector SkillList; - StatsWindow(MWBase::WindowManager& parWindowManager); + StatsWindow(); /// automatically updates all the data in the stats window, but only if it has changed. void onFrame(); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 071971befb..ab2936cfce 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -5,8 +5,8 @@ using namespace MWGui; -TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_text_input.layout", parWindowManager) +TextInputDialog::TextInputDialog() + : WindowModal("openmw_text_input.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index 6b371bae74..1f53263ecd 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -13,7 +13,7 @@ namespace MWGui class TextInputDialog : public WindowModal { public: - TextInputDialog(MWBase::WindowManager& parWindowManager); + TextInputDialog(); std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7730019e83..2250ffd0b5 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -19,7 +19,7 @@ using namespace MWGui; using namespace MyGUI; -ToolTips::ToolTips(MWBase::WindowManager* windowManager) : +ToolTips::ToolTips() : Layout("openmw_tooltips.layout") , mGameMode(true) , mFullHelp(false) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index e4fcb310c8..f8f256167b 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -39,7 +39,7 @@ namespace MWGui class ToolTips : public OEngine::GUI::Layout { public: - ToolTips(MWBase::WindowManager* windowManager); + ToolTips(); void onFrame(float frameDuration); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 718e6378bb..718f40c785 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -24,8 +24,8 @@ namespace MWGui const float TradeWindow::sBalanceChangeInitialPause = 0.5; const float TradeWindow::sBalanceChangeInterval = 0.1; - TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_trade_window.layout", parWindowManager) + TradeWindow::TradeWindow() : + WindowBase("openmw_trade_window.layout") , ContainerBase(NULL) // no drag&drop , mCurrentBalance(0) , mBalanceButtonsState(BBS_None) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 111c0935fe..e526a42ca5 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -23,7 +23,7 @@ namespace MWGui class TradeWindow : public ContainerBase, public WindowBase { public: - TradeWindow(MWBase::WindowManager& parWindowManager); + TradeWindow(); void startTrade(MWWorld::Ptr actor); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index c2b543a4fd..f85a8be594 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -20,8 +20,8 @@ namespace MWGui { - TrainingWindow::TrainingWindow(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_trainingwindow.layout", parWindowManager) + TrainingWindow::TrainingWindow() + : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) { getWidget(mTrainingOptions, "TrainingOptions"); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index d6be60ae67..740115cdfc 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -10,7 +10,7 @@ namespace MWGui class TrainingWindow : public WindowBase, public ReferenceInterface { public: - TrainingWindow(MWBase::WindowManager& parWindowManager); + TrainingWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index b710171669..0a74c921af 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -25,8 +25,8 @@ namespace MWGui { const int TravelWindow::sLineHeight = 18; - TravelWindow::TravelWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_travel_window.layout", parWindowManager) + TravelWindow::TravelWindow() : + WindowBase("openmw_travel_window.layout") , mCurrentY(0) , mLastPos(0) { diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 61b724910c..a814d04785 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -23,7 +23,7 @@ namespace MWGui class TravelWindow : public ReferenceInterface, public WindowBase { public: - TravelWindow(MWBase::WindowManager& parWindowManager); + TravelWindow(); void startTravel(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 69dfa10b4d..a84b9203a9 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -25,8 +25,8 @@ namespace MWGui { - WaitDialogProgressBar::WaitDialogProgressBar(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_wait_dialog_progressbar.layout", parWindowManager) + WaitDialogProgressBar::WaitDialogProgressBar() + : WindowBase("openmw_wait_dialog_progressbar.layout") { getWidget(mProgressBar, "ProgressBar"); getWidget(mProgressText, "ProgressText"); @@ -46,9 +46,9 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - WaitDialog::WaitDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_wait_dialog.layout", parWindowManager) - , mProgressBar(parWindowManager) + WaitDialog::WaitDialog() + : WindowBase("openmw_wait_dialog.layout") + , mProgressBar() , mWaiting(false) , mSleeping(false) , mHours(1) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 4510e665b3..d06d7d1128 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui class WaitDialogProgressBar : public WindowBase { public: - WaitDialogProgressBar(MWBase::WindowManager& parWindowManager); + WaitDialogProgressBar(); virtual void open(); @@ -23,7 +23,7 @@ namespace MWGui class WaitDialog : public WindowBase { public: - WaitDialog(MWBase::WindowManager& parWindowManager); + WaitDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 3801ae6f7a..dd3206ed65 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -34,8 +34,7 @@ void MWGui::Widgets::fixTexturePath(std::string &path) /* MWSkill */ MWSkill::MWSkill() - : mManager(NULL) - , mSkillId(ESM::Skill::Length) + : mSkillId(ESM::Skill::Length) , mSkillNameWidget(NULL) , mSkillValueWidget(NULL) { @@ -65,7 +64,7 @@ void MWSkill::setSkillValue(const SkillValue& value) void MWSkill::updateWidgets() { - if (mSkillNameWidget && mManager) + if (mSkillNameWidget) { if (mSkillId == ESM::Skill::Length) { @@ -73,7 +72,7 @@ void MWSkill::updateWidgets() } else { - const std::string &name = mManager->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); static_cast(mSkillNameWidget)->setCaption(name); } } @@ -126,8 +125,7 @@ void MWSkill::initialiseOverride() /* MWAttribute */ MWAttribute::MWAttribute() - : mManager(NULL) - , mId(-1) + : mId(-1) , mAttributeNameWidget(NULL) , mAttributeValueWidget(NULL) { @@ -152,7 +150,7 @@ void MWAttribute::onClicked(MyGUI::Widget* _sender) void MWAttribute::updateWidgets() { - if (mAttributeNameWidget && mManager) + if (mAttributeNameWidget) { if (mId < 0 || mId >= 8) { @@ -170,7 +168,7 @@ void MWAttribute::updateWidgets() "sAttributePersonality", "sAttributeLuck" }; - const std::string &name = mManager->getGameSettingString(attributes[mId], ""); + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); static_cast(mAttributeNameWidget)->setCaption(name); } } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 26ca750667..038ce3f86f 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -98,7 +98,6 @@ namespace MWGui void setSkillNumber(int skillId); void setSkillValue(const SkillValue& value); - MWBase::WindowManager *getWindowManager() const { return mManager; } ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } const SkillValue& getSkillValue() const { return mValue; } @@ -121,7 +120,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager *mManager; ESM::Skill::SkillEnum mSkillId; SkillValue mValue; MyGUI::Widget* mSkillNameWidget; @@ -140,7 +138,6 @@ namespace MWGui void setAttributeId(int attributeId); void setAttributeValue(const AttributeValue& value); - MWBase::WindowManager *getWindowManager() const { return mManager; } int getAttributeId() const { return mId; } const AttributeValue& getAttributeValue() const { return mValue; } @@ -163,7 +160,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager *mManager; int mId; AttributeValue mValue; MyGUI::Widget* mAttributeNameWidget; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index cb3d4ea8c8..c41bcb7ce6 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -6,7 +6,7 @@ using namespace MWGui; -WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) +WindowBase::WindowBase(const std::string& parLayout) : Layout(parLayout) { } @@ -38,8 +38,8 @@ void WindowBase::center() mMainWidget->setCoord(coord); } -WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager) +WindowModal::WindowModal(const std::string& parLayout) + : WindowBase(parLayout) { } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index a2cb731fee..2c014baf0b 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -15,7 +15,7 @@ namespace MWGui class WindowBase: public OEngine::GUI::Layout { public: - WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowBase(const std::string& parLayout); // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; @@ -38,7 +38,7 @@ namespace MWGui class WindowModal : public WindowBase { public: - WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowModal(const std::string& parLayout); virtual void open(); virtual void close(); }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bcde82e966..f2ded8813e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -162,38 +162,38 @@ WindowManager::WindowManager( mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; mMenu = new MainMenu(w,h); - mMap = new MapWindow(*this, cacheDir); - mStatsWindow = new StatsWindow(*this); + mMap = new MapWindow(cacheDir); + mStatsWindow = new StatsWindow(); mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(*this); - mMessageBoxManager = new MessageBoxManager(this); - mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); - mTradeWindow = new TradeWindow(*this); - mSpellBuyingWindow = new SpellBuyingWindow(*this); - mTravelWindow = new TravelWindow(*this); - mDialogueWindow = new DialogueWindow(*this); - mContainerWindow = new ContainerWindow(*this,mDragAndDrop); + mJournal = new JournalWindow(); + mMessageBoxManager = new MessageBoxManager(); + mInventoryWindow = new InventoryWindow(mDragAndDrop); + mTradeWindow = new TradeWindow(); + mSpellBuyingWindow = new SpellBuyingWindow(); + mTravelWindow = new TravelWindow(); + mDialogueWindow = new DialogueWindow(); + mContainerWindow = new ContainerWindow(mDragAndDrop); mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); - mToolTips = new ToolTips(this); - mScrollWindow = new ScrollWindow(*this); - mBookWindow = new BookWindow(*this); - mCountDialog = new CountDialog(*this); - mSettingsWindow = new SettingsWindow(*this); - mConfirmationDialog = new ConfirmationDialog(*this); - mAlchemyWindow = new AlchemyWindow(*this); - mSpellWindow = new SpellWindow(*this); - mQuickKeysMenu = new QuickKeysMenu(*this); - mLevelupDialog = new LevelupDialog(*this); - mWaitDialog = new WaitDialog(*this); - mSpellCreationDialog = new SpellCreationDialog(*this); - mEnchantingDialog = new EnchantingDialog(*this); - mTrainingWindow = new TrainingWindow(*this); - mMerchantRepair = new MerchantRepair(*this); - mRepair = new Repair(*this); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mBookWindow = new BookWindow(); + mCountDialog = new CountDialog(); + mSettingsWindow = new SettingsWindow(); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); + mSpellWindow = new SpellWindow(); + mQuickKeysMenu = new QuickKeysMenu(); + mLevelupDialog = new LevelupDialog(); + mWaitDialog = new WaitDialog(); + mSpellCreationDialog = new SpellCreationDialog(); + mEnchantingDialog = new EnchantingDialog(); + mTrainingWindow = new TrainingWindow(); + mMerchantRepair = new MerchantRepair(); + mRepair = new Repair(); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(*this, mDragAndDrop, mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); mLoadingScreen->onResChange (w,h); mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); @@ -202,7 +202,7 @@ WindowManager::WindowManager( mHud->setVisible(mHudEnabled); - mCharGen = new CharacterCreation(this); + mCharGen = new CharacterCreation(); // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 54ed082cf9..56868306ac 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -6,8 +6,8 @@ using namespace MWGui; -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) +WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) + : WindowBase(parLayout), mPinned(false), mVisible(false) { ExposedWindow* window = static_cast(mMainWidget); mPinButton = window->getSkinWidget ("Button"); diff --git a/apps/openmw/mwgui/windowpinnablebase.hpp b/apps/openmw/mwgui/windowpinnablebase.hpp index 657e8142f1..1ab6294328 100644 --- a/apps/openmw/mwgui/windowpinnablebase.hpp +++ b/apps/openmw/mwgui/windowpinnablebase.hpp @@ -10,7 +10,7 @@ namespace MWGui class WindowPinnableBase: public WindowBase { public: - WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowPinnableBase(const std::string& parLayout); bool pinned() { return mPinned; } private: From 3a87b12bafefd6b7f97c9a2ddac43fddc496d549 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 21:31:14 +0200 Subject: [PATCH 1036/1483] delete script subview on script deletion --- apps/opencs/view/world/scriptsubview.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 2fdb44aec3..0319033b00 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -53,8 +53,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); -// connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int start, int end)), -// this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int start, int end))); + connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); } void CSVWorld::ScriptSubView::setEditLock (bool locked) @@ -88,5 +88,8 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) { + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + if (!parent.isValid() && index.row()>=start && index.row()<=end) + deleteLater(); } \ No newline at end of file From 6c6750342c321b537fcc7cc14246050fc4bf2580 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 13:37:20 -0700 Subject: [PATCH 1037/1483] Specified particle size is actually the radius --- components/nif/data.hpp | 4 ++-- components/nifogre/ogrenifloader.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index bd109041f1..f1f34184ba 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -167,7 +167,7 @@ class NiAutoNormalParticlesData : public ShapeData public: int numParticles; - float particleSize; + float particleRadius; int activeCount; @@ -180,7 +180,7 @@ public: // Should always match the number of vertices numParticles = nif->getUShort(); - particleSize = nif->getFloat(); + particleRadius = nif->getFloat(); activeCount = nif->getUShort(); if(nif->getInt()) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3c876283e1..62732d387d 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1543,7 +1543,8 @@ class NIFObjectLoader : Ogre::ManualResourceLoader vertprop, zprop, specprop, wireprop, needTangents)); - partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); + partsys->setDefaultDimensions(particledata->particleRadius*2.0f, + particledata->particleRadius*2.0f); partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); From 74145410f24d6c60b6cdca81aa14e40564691cda Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 22:49:22 +0200 Subject: [PATCH 1038/1483] basic syntax highlighting in script subview --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/world/scriptcontext.cpp | 22 ++++ apps/opencs/model/world/scriptcontext.hpp | 26 +++++ apps/opencs/view/world/scripthighlighter.cpp | 105 +++++++++++++++++++ apps/opencs/view/world/scripthighlighter.hpp | 77 ++++++++++++++ apps/opencs/view/world/scriptsubview.cpp | 4 + components/CMakeLists.txt | 2 +- components/compiler/nullerrorhandler.cpp | 6 ++ components/compiler/nullerrorhandler.hpp | 21 ++++ 9 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/world/scriptcontext.cpp create mode 100644 apps/opencs/model/world/scriptcontext.hpp create mode 100644 apps/opencs/view/world/scripthighlighter.cpp create mode 100644 apps/opencs/view/world/scripthighlighter.hpp create mode 100644 components/compiler/nullerrorhandler.cpp create mode 100644 components/compiler/nullerrorhandler.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bd882892fd..5c15938bda 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -22,7 +22,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid data record idcollection commands columnbase + universalid data record idcollection commands columnbase scriptcontext ) opencs_hdrs_noqt (model/world @@ -59,7 +59,7 @@ opencs_units (view/world ) opencs_units_noqt (view/world - dialoguesubview util subviews enumdelegate vartypedelegate + dialoguesubview util subviews enumdelegate vartypedelegate scripthighlighter ) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp new file mode 100644 index 0000000000..69b72abf26 --- /dev/null +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -0,0 +1,22 @@ + +#include "scriptcontext.hpp" + +bool CSMWorld::ScriptContext::canDeclareLocals() const +{ + return false; +} + +char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const +{ + return ' '; +} + +char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const +{ + return ' '; +} + +bool CSMWorld::ScriptContext::isId (const std::string& name) const +{ + return false; +} \ No newline at end of file diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp new file mode 100644 index 0000000000..1231aea649 --- /dev/null +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_WORLD_SCRIPTCONTEXT_H +#define CSM_WORLD_SCRIPTCONTEXT_H + +#include + +namespace CSMWorld +{ + class ScriptContext : public Compiler::Context + { + public: + + virtual bool canDeclareLocals() const; + ///< Is the compiler allowed to declare local variables? + + virtual char getGlobalType (const std::string& name) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + + virtual char getMemberType (const std::string& name, const std::string& id) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + + virtual bool isId (const std::string& name) const; + ///< Does \a name match an ID, that can be referenced? + }; +} + +#endif diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp new file mode 100644 index 0000000000..1e93ac26b7 --- /dev/null +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -0,0 +1,105 @@ + +#include "scripthighlighter.hpp" + +#include + +#include + +bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Int); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseFloat (float value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Float); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Name); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseKeyword (int keyword, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Keyword); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseSpecial (int code, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Special); + return true; +} + +void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner) +{} + +void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type type) +{ + int length = static_cast (loc.mLiteral.size()); + + int index = loc.mColumn; + + // compensate for bug in Compiler::Scanner (position of token is the character after the token) + index -= length; + + setFormat (index, length, mScheme[type]); +} + +CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) +: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext) +{ + /// \ŧodo replace this with user settings + { + QTextCharFormat format; + format.setForeground (Qt::darkMagenta); + mScheme.insert (std::make_pair (Type_Int, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::green); + mScheme.insert (std::make_pair (Type_Float, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::gray); + mScheme.insert (std::make_pair (Type_Name, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::red); + mScheme.insert (std::make_pair (Type_Keyword, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::darkYellow); + mScheme.insert (std::make_pair (Type_Special, format)); + } +} + +void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) +{ + std::istringstream stream (text.toUtf8().constData()); + + Compiler::Scanner scanner (mErrorHandler, stream, mContext.getExtensions()); + + try + { + scanner.scan (*this); + } + catch (...) {} // ignore syntax errors + +} \ No newline at end of file diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp new file mode 100644 index 0000000000..e9918f99b7 --- /dev/null +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -0,0 +1,77 @@ +#ifndef CSV_WORLD_SCRIPTHIGHLIGHTER_H +#define CSV_WORLD_SCRIPTHIGHLIGHTER_H + +#include + +#include + +#include +#include + +#include "../../model/world/scriptcontext.hpp" + +namespace CSVWorld +{ + class ScriptHighlighter : public QSyntaxHighlighter, private Compiler::Parser + { + public: + + enum Type + { + Type_Int, + Type_Float, + Type_Name, + Type_Keyword, + Type_Special + }; + + private: + + Compiler::NullErrorHandler mErrorHandler; + CSMWorld::ScriptContext mContext; + std::map mScheme; + + private: + + virtual bool parseInt (int value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle an int token. + /// \return fetch another token? + + virtual bool parseFloat (float value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a float token. + /// \return fetch another token? + + virtual bool parseName (const std::string& name, + const Compiler::TokenLoc& loc, Compiler::Scanner& scanner); + ///< Handle a name token. + /// \return fetch another token? + + virtual bool parseKeyword (int keyword, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + + virtual bool parseSpecial (int code, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + ///< Handle a special character token. + /// \return fetch another token? + + virtual void parseEOF (Compiler::Scanner& scanner); + ///< Handle EOF token. + + void highlight (const Compiler::TokenLoc& loc, Type type); + + public: + + ScriptHighlighter (QTextDocument *parent); + + virtual void highlightBlock (const QString& text); + }; +} + +#endif diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0319033b00..ab1c2d57c6 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -12,6 +12,8 @@ #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" +#include "scripthighlighter.hpp" + CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) { ++mView.mChangeLocked; @@ -55,6 +57,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); + + new ScriptHighlighter (mEditor->document()); } void CSVWorld::ScriptSubView::setEditLock (bool locked) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a2f416fcca..ed12ff2f0e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -54,7 +54,7 @@ add_component_dir (files add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler - stringparser tokenloc + stringparser tokenloc nullerrorhandler ) add_component_dir (interpreter diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp new file mode 100644 index 0000000000..3071701e8a --- /dev/null +++ b/components/compiler/nullerrorhandler.cpp @@ -0,0 +1,6 @@ + +#include "nullerrorhandler.hpp" + +void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} + +void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} \ No newline at end of file diff --git a/components/compiler/nullerrorhandler.hpp b/components/compiler/nullerrorhandler.hpp new file mode 100644 index 0000000000..bb4db99a28 --- /dev/null +++ b/components/compiler/nullerrorhandler.hpp @@ -0,0 +1,21 @@ + +#ifndef COMPILER_NULLERRORHANDLER_H_INCLUDED +#define COMPILER_NULLERRORHANDLER_H_INCLUDED + +#include "errorhandler.hpp" + +namespace Compiler +{ + /// \brief Error handler implementation: Ignore all error messages + + class NullErrorHandler : public ErrorHandler + { + virtual void report (const std::string& message, const TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + }; +} + +#endif From 106ef4c9369e303aaf79654c597961e1516f3522 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 10 Apr 2013 22:53:03 +0200 Subject: [PATCH 1039/1483] Rotate script --- apps/openmw/mwscript/docs/vmformat.txt | 4 +- .../mwscript/transformationextensions.cpp | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7e9827062b..7810c2874b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -318,5 +318,7 @@ op 0x20001fb: DropSoulGem, explicit reference op 0x20001fc: OnDeath op 0x20001fd: IsWerewolf op 0x20001fe: IsWerewolf, explicit reference +op 0x20001ff: Rotate +op 0x2000200: Rotate, explicit reference -opcodes 0x20001ff-0x3ffffff unused +opcodes 0x2000201-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 49688efb5d..6c4fb0f4bd 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -542,6 +542,42 @@ namespace MWScript } }; + template + class OpRotate : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why + runtime.pop(); + + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + + //Axis in morrowind are inverted + if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + } + else if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -568,6 +604,8 @@ namespace MWScript const int opcodePlaceAtMeExplicit = 0x200019e; const int opcodeModScale = 0x20001e3; const int opcodeModScaleExplicit = 0x20001e4; + const int opcodeRotate = 0x20001ff; + const int opcodeRotateExplicit = 0x2000200; void registerExtensions (Compiler::Extensions& extensions) { @@ -585,6 +623,7 @@ namespace MWScript extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); + extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -614,6 +653,8 @@ namespace MWScript interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); interpreter.installSegment5(opcodeModScale,new OpModScale); interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); + interpreter.installSegment5(opcodeRotate,new OpRotate); + interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); } } } From caff28e20acb914997143e51ac503835f3a8fb4d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 19:58:17 -0700 Subject: [PATCH 1040/1483] Move NIFSkeletonLoader to a separate file --- apps/openmw/mwrender/animation.hpp | 3 + components/CMakeLists.txt | 2 +- components/nifogre/ogrenifloader.cpp | 366 +-------------------------- components/nifogre/ogrenifloader.hpp | 4 +- components/nifogre/skeleton.cpp | 351 +++++++++++++++++++++++++ components/nifogre/skeleton.hpp | 63 +++++ 6 files changed, 421 insertions(+), 368 deletions(-) create mode 100644 components/nifogre/skeleton.cpp create mode 100644 components/nifogre/skeleton.hpp diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cfef28f16c..029c56523d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,6 +1,9 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H +#include +#include + #include #include "../mwworld/ptr.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a2f416fcca..d43725ee08 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader + ogrenifloader skeleton ) add_component_dir (nifbullet diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 62732d387d..0a30f38bd1 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -51,7 +51,7 @@ #include #include -typedef unsigned char ubyte; +#include "skeleton.hpp" namespace std { @@ -424,370 +424,6 @@ public: }; -/** Manual resource loader for NIF skeletons. This is the main class - responsible for translating the internal NIF skeleton structure into - something Ogre can use (includes animations and node TextKeyData). - */ -class 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(); -} - - -static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) -{ - Ogre::Animation *anim = skel->createAnimation(name, stopTime); - - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *kfc = ctrls[i]; - if(kfc->data.empty()) - continue; - const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - - Ogre::Bone *bone = skel->getBone(targets[i]); - // NOTE: For some reason, Ogre doesn't like the node track ID being different from - // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? - anim->getNodeTrack(bone->getHandle()) : - anim->createNodeTrack(bone->getHandle(), bone); - - 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 = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - - bool didlast = false; - while(!didlast) - { - float curtime = std::numeric_limits::max(); - - //Get latest time - 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, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::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 - { - Nif::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 - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); -} - - -static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) -{ - TextKeyMap textkeys; - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - return textkeys; -} - -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) -{ - Ogre::Bone *bone; - if(!skel->hasBone(node->name)) - bone = skel->createBone(node->name); - else - bone = skel->createBone(); - if(parent) parent->addChild(bone); - mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); - - bone->setOrientation(node->trafo.rotation); - bone->setPosition(node->trafo.pos); - bone->setScale(Ogre::Vector3(node->trafo.scale)); - bone->setBindingPose(); - - if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ - node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ - node->recType == Nif::RC_NiCamera || - node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles - )) - warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController - )) - warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); - ctrl = ctrl->next; - } - - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - textkeys = extractTextKeys(tk); - animroot = bone; - } - e = e->extra; - } - - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); - } - } -} - -// Lookup to retrieve an Ogre bone handle for a given Nif record index -std::map mNifToOgreHandleMap; - -typedef std::map LoaderMap; -static LoaderMap sLoaders; - -public: -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::ptr nif(Nif::NIFFile::create(skel->getName())); - const Nif::Node *node = static_cast(nif->getRoot(0)); - - std::vector ctrls; - Ogre::Bone *animroot = NULL; - TextKeyMap textkeys; - try { - buildBones(skel, node, animroot, textkeys, ctrls); - } - catch(std::exception &e) { - std::cerr<< "Exception while loading "<getName() < 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++) - { - const 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; - } - - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); - bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); - - std::string currentgroup; - TextKeyMap::const_iterator keyiter = textkeys.begin(); - for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) - { - std::string::size_type sep = keyiter->second.find(':'); - if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || - (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) - continue; - currentgroup = keyiter->second.substr(0, sep); - - if(skel->hasAnimation(currentgroup)) - continue; - - TextKeyMap::const_iterator lastkeyiter = textkeys.end(); - while((--lastkeyiter)->first > keyiter->first) - { - if(lastkeyiter->second.find(':') == currentgroup.length() && - lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) - break; - } - - buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - - TextKeyMap::const_iterator insiter(keyiter); - TextKeyMap groupkeys; - do { - sep = insiter->second.find(':'); - if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); - else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first, insiter->second)); - } while(insiter++ != lastkeyiter); - - bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); - } -} - - -static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) -{ - /* We need to be a little aggressive here, since some NIFs have a crap-ton - * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: - * There are no bones used for skinning, there are no controllers on non- - * NiTriShape nodes, there are no nodes named "AttachLight", and the tree - * consists of NiNode, NiTriShape, and RootCollisionNode types only. - */ - if(!node->boneTrafo) - { - if(node->recType == Nif::RC_NiTriShape) - return Ogre::SkeletonPtr(); - if(node->controller.empty() && node->name != "AttachLight") - { - if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) - { - const Nif::NiNode *ninode = static_cast(node); - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); - if(!skel.isNull()) - return skel; - } - } - return Ogre::SkeletonPtr(); - } - } - } - - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - return skelMgr.create(name, group, true, &sLoaders[name]); -} - -// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be -// used when the bone name is insufficient as this is a relatively slow lookup -static int lookupOgreBoneHandle(const std::string &nifname, int idx) -{ - LoaderMap::const_iterator loader = sLoaders.find(nifname); - if(loader != sLoaders.end()) - { - std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); - if(entry != loader->second.mNifToOgreHandleMap.end()) - return entry->second; - } - throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); -} - -}; -NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; - - // Conversion of blend / test mode from NIF static const char *getBlendFactor(int mode) { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 18bbf0200f..fa5182aeaa 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -25,11 +25,11 @@ #define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP #include -#include -#include +#include #include #include +#include // FIXME: This namespace really doesn't do anything Nif-specific. Any supportable diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp new file mode 100644 index 0000000000..e97e91ef03 --- /dev/null +++ b/components/nifogre/skeleton.cpp @@ -0,0 +1,351 @@ +#include "skeleton.hpp" + +#include +#include +#include +#include + +#include +#include + +namespace NifOgre +{ + +void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) +{ + Ogre::Animation *anim = skel->createAnimation(name, stopTime); + + for(size_t i = 0;i < ctrls.size();i++) + { + const Nif::NiKeyframeController *kfc = ctrls[i]; + if(kfc->data.empty()) + continue; + const Nif::NiKeyframeData *kf = kfc->data.getPtr(); + + /* Get the keyframes and make sure they're sorted first to last */ + const Nif::QuaternionKeyList &quatkeys = kf->mRotations; + const Nif::Vector3KeyList &trankeys = kf->mTranslations; + const Nif::FloatKeyList &scalekeys = kf->mScales; + + Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + + Ogre::Bone *bone = skel->getBone(targets[i]); + // NOTE: For some reason, Ogre doesn't like the node track ID being different from + // the bone ID + Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? + anim->getNodeTrack(bone->getHandle()) : + anim->createNodeTrack(bone->getHandle(), bone); + + 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 = quatiter->mValue; + if(traniter != trankeys.mKeys.end()) + lasttrans = curtrans = traniter->mValue; + if(scaleiter != scalekeys.mKeys.end()) + lastscale = curscale = Ogre::Vector3(scaleiter->mValue); + + bool didlast = false; + while(!didlast) + { + float curtime = std::numeric_limits::max(); + + //Get latest time + 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, startTime); + if(curtime >= stopTime) + { + didlast = true; + curtime = stopTime; + } + + // Get the latest quaternions, translations, and scales for the + // current time + while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) + { + lastquat = curquat; + if(++quatiter != quatkeys.mKeys.end()) + curquat = quatiter->mValue; + } + while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) + { + lasttrans = curtrans; + if(++traniter != trankeys.mKeys.end()) + curtrans = traniter->mValue; + } + while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) + { + lastscale = curscale; + if(++scaleiter != scalekeys.mKeys.end()) + curscale = Ogre::Vector3(scaleiter->mValue); + } + + Ogre::TransformKeyFrame *kframe; + kframe = nodetrack->createNodeKeyFrame(curtime); + if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) + kframe->setRotation(curquat); + else + { + Nif::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 + { + Nif::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 + { + Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; + float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); + kframe->setScale(lastscale + ((curscale-lastscale)*diff)); + } + } + } + anim->optimise(); +} + + +TextKeyMap NIFSkeletonLoader::extractTextKeys(const Nif::NiTextKeyExtraData *tk) +{ + TextKeyMap textkeys; + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + return textkeys; +} + +void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent) +{ + Ogre::Bone *bone; + if(!skel->hasBone(node->name)) + bone = skel->createBone(node->name); + else + bone = skel->createBone(); + if(parent) parent->addChild(bone); + mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); + + bone->setOrientation(node->trafo.rotation); + bone->setPosition(node->trafo.pos); + bone->setScale(Ogre::Vector3(node->trafo.scale)); + bone->setBindingPose(); + + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiCamera || + node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles + )) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiKeyframeController) + ctrls.push_back(static_cast(ctrl.getPtr())); + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController + )) + warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); + ctrl = ctrl->next; + } + + Nif::ExtraPtr e = node->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + textkeys = extractTextKeys(tk); + animroot = bone; + } + e = e->extra; + } + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); + } + } +} + +void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) +{ + Ogre::Skeleton *skel = dynamic_cast(resource); + OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); + + Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); + const Nif::Node *node = static_cast(nif->getRoot(0)); + + std::vector ctrls; + Ogre::Bone *animroot = NULL; + TextKeyMap textkeys; + try { + buildBones(skel, node, animroot, textkeys, ctrls); + } + catch(std::exception &e) { + std::cerr<< "Exception while loading "<getName() < 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++) + { + const 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; + } + + Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); + bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); + + std::string currentgroup; + TextKeyMap::const_iterator keyiter = textkeys.begin(); + for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) + { + std::string::size_type sep = keyiter->second.find(':'); + if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || + (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) + continue; + currentgroup = keyiter->second.substr(0, sep); + + if(skel->hasAnimation(currentgroup)) + continue; + + TextKeyMap::const_iterator lastkeyiter = textkeys.end(); + while((--lastkeyiter)->first > keyiter->first) + { + if(lastkeyiter->second.find(':') == currentgroup.length() && + lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) + break; + } + + buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + + TextKeyMap::const_iterator insiter(keyiter); + TextKeyMap groupkeys; + do { + sep = insiter->second.find(':'); + if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) + groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); + else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) + groupkeys.insert(std::make_pair(insiter->first, insiter->second)); + } while(insiter++ != lastkeyiter); + + bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); + } +} + + +Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) +{ + /* We need to be a little aggressive here, since some NIFs have a crap-ton + * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: + * There are no bones used for skinning, there are no controllers on non- + * NiTriShape nodes, there are no nodes named "AttachLight", and the tree + * consists of NiNode, NiTriShape, and RootCollisionNode types only. + */ + if(!node->boneTrafo) + { + if(node->recType == Nif::RC_NiTriShape) + return Ogre::SkeletonPtr(); + if(node->controller.empty() && node->name != "AttachLight") + { + if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) + { + const Nif::NiNode *ninode = static_cast(node); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + { + Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); + if(!skel.isNull()) + return skel; + } + } + return Ogre::SkeletonPtr(); + } + } + } + + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + return skelMgr.create(name, group, true, &sLoaders[name]); +} + +// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be +// used when the bone name is insufficient as this is a relatively slow lookup +int NIFSkeletonLoader::lookupOgreBoneHandle(const std::string &nifname, int idx) +{ + LoaderMap::const_iterator loader = sLoaders.find(nifname); + if(loader != sLoaders.end()) + { + std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); + if(entry != loader->second.mNifToOgreHandleMap.end()) + return entry->second; + } + throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); +} + +NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; + +} diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp new file mode 100644 index 0000000000..c69c2a12fe --- /dev/null +++ b/components/nifogre/skeleton.hpp @@ -0,0 +1,63 @@ +#ifndef COMPONENTS_NIFOGRE_SKELETON_HPP +#define COMPONENTS_NIFOGRE_SKELETON_HPP + +#include +#include +#include + +#include + +#include "ogrenifloader.hpp" + +namespace Nif +{ + class NiTextKeyExtraData; + class Node; + class NiKeyframeController; +} + +namespace NifOgre +{ + +/** Manual resource loader for NIF skeletons. This is the main class + responsible for translating the internal NIF skeleton structure into + something Ogre can use (includes animations and node TextKeyData). + */ +class 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(); + } + + static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); + + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); + void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); + + // Lookup to retrieve an Ogre bone handle for a given Nif record index + std::map mNifToOgreHandleMap; + + typedef std::map LoaderMap; + static LoaderMap sLoaders; + +public: + void loadResource(Ogre::Resource *resource); + + static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); + + // Looks up an Ogre Bone handle ID from a NIF's record index. Should only + // be used when the bone name is insufficient as this is a relatively slow + // lookup + static int lookupOgreBoneHandle(const std::string &nifname, int idx); +}; + +} + +#endif From 39704077722ec64120d6764b8a7e0480cac051be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 20:22:13 -0700 Subject: [PATCH 1041/1483] Use actual classes for properties --- components/nif/property.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index fd96ad0481..06c8260ce5 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -156,11 +156,11 @@ public: }; // These contain no other data than the 'flags' field in Property -typedef Property NiShadeProperty; -typedef Property NiDitherProperty; -typedef Property NiZBufferProperty; -typedef Property NiSpecularProperty; -typedef Property NiWireframeProperty; +class NiShadeProperty : public Property { }; +class NiDitherProperty : public Property { }; +class NiZBufferProperty : public Property { }; +class NiSpecularProperty : public Property { }; +class NiWireframeProperty : public Property { }; // The rest are all struct-based template @@ -324,10 +324,10 @@ struct S_StencilProperty } }; -typedef StructPropT NiAlphaProperty; -typedef StructPropT NiMaterialProperty; -typedef StructPropT NiVertexColorProperty; -typedef StructPropT NiStencilProperty; +class NiAlphaProperty : public StructPropT { }; +class NiMaterialProperty : public StructPropT { }; +class NiVertexColorProperty : public StructPropT { }; +class NiStencilProperty : public StructPropT { }; } // Namespace #endif From 75489b1e9d583da765dc3da4aedea0f9e8e7fa9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 20:24:44 -0700 Subject: [PATCH 1042/1483] Move NIFMaterialLoader to a separate file --- components/CMakeLists.txt | 2 +- components/nifogre/material.cpp | 399 ++++++++++++++++++++++++++ components/nifogre/material.hpp | 57 ++++ components/nifogre/ogrenifloader.cpp | 407 +-------------------------- 4 files changed, 458 insertions(+), 407 deletions(-) create mode 100644 components/nifogre/material.cpp create mode 100644 components/nifogre/material.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d43725ee08..aa422b49e7 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader skeleton + ogrenifloader skeleton material ) add_component_dir (nifbullet diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp new file mode 100644 index 0000000000..431b8219a9 --- /dev/null +++ b/components/nifogre/material.cpp @@ -0,0 +1,399 @@ +#include "material.hpp" + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + + +namespace NifOgre +{ + +// Conversion of blend / test mode from NIF +static const char *getBlendFactor(int mode) +{ + switch(mode) + { + case 0: return "one"; + case 1: return "zero"; + case 2: return "src_colour"; + case 3: return "one_minus_src_colour"; + case 4: return "dest_colour"; + case 5: return "one_minus_dest_colour"; + case 6: return "src_alpha"; + case 7: return "one_minus_src_alpha"; + case 8: return "dest_alpha"; + case 9: return "one_minus_dest_alpha"; + case 10: return "src_alpha_saturate"; + } + std::cerr<< "Unexpected blend mode: "<colors.size() != 0); + + // Texture + if(texprop) + { + for(int i = 0;i < 7;i++) + { + if(!texprop->textures[i].inUse) + continue; + if(texprop->textures[i].texture.empty()) + { + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); + continue; + } + + const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); + if(st->external) + texName[i] = findTextureName(st->filename); + else + warn("Found internal texture, ignoring."); + } + + Nif::ControllerPtr ctrls = texprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled texture controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); + + // Alpha modifiers + if(alphaprop) + { + alphaFlags = alphaprop->flags; + alphaTest = alphaprop->data.threshold; + + Nif::ControllerPtr ctrls = alphaprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled alpha controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + // Vertex color handling + if(vertprop) + { + vertMode = vertprop->data.vertmode; + // FIXME: Handle lightmode? + //lightMode = vertprop->data.lightmode; + + Nif::ControllerPtr ctrls = vertprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(zprop) + { + depthFlags = zprop->flags; + // Depth function??? + + Nif::ControllerPtr ctrls = zprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled depth controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(specprop) + { + specFlags = specprop->flags; + + Nif::ControllerPtr ctrls = specprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled specular controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(wireprop) + { + wireFlags = wireprop->flags; + + Nif::ControllerPtr ctrls = wireprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + // Material + if(matprop) + { + ambient = matprop->data.ambient; + diffuse = matprop->data.diffuse; + specular = matprop->data.specular; + emissive = matprop->data.emissive; + glossiness = matprop->data.glossiness; + alpha = matprop->data.alpha; + + Nif::ControllerPtr ctrls = matprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled material controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + { + // Generate a hash out of all properties that can affect the material. + size_t h = 0; + boost::hash_combine(h, ambient.x); + boost::hash_combine(h, ambient.y); + boost::hash_combine(h, ambient.z); + boost::hash_combine(h, diffuse.x); + boost::hash_combine(h, diffuse.y); + boost::hash_combine(h, diffuse.z); + boost::hash_combine(h, alpha); + boost::hash_combine(h, specular.x); + boost::hash_combine(h, specular.y); + boost::hash_combine(h, specular.z); + boost::hash_combine(h, glossiness); + boost::hash_combine(h, emissive.x); + boost::hash_combine(h, emissive.y); + boost::hash_combine(h, emissive.z); + for(int i = 0;i < 7;i++) + { + if(!texName[i].empty()) + boost::hash_combine(h, texName[i]); + } + boost::hash_combine(h, vertexColour); + boost::hash_combine(h, alphaFlags); + boost::hash_combine(h, alphaTest); + boost::hash_combine(h, vertMode); + boost::hash_combine(h, depthFlags); + boost::hash_combine(h, specFlags); + boost::hash_combine(h, wireFlags); + + std::map::iterator itr = sMaterialMap.find(h); + if (itr != sMaterialMap.end()) + { + // a suitable material exists already - use it + return itr->second; + } + // not found, create a new one + sMaterialMap.insert(std::make_pair(h, name)); + } + + // No existing material like this. Create a new one. + sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); + if(vertMode == 0 || !vertexColour) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); + } + else if(vertMode == 1) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); + } + else if(vertMode == 2) + { + instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); + } + else + std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( + new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); + } + + if(wireFlags) + { + instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); + } + + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); + instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); + if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) + { + instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) + { + instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) + { + // force automips on normal maps for now + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); + } + + for(int i = 0;i < 7;i++) + { + if(i == Nif::NiTexturingProperty::BaseTexture || + i == Nif::NiTexturingProperty::DetailTexture || + i == Nif::NiTexturingProperty::BumpTexture || + i == Nif::NiTexturingProperty::GlowTexture) + continue; + if(!texName[i].empty()) + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); + } + + if (vertexColour) + instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); + + // Add transparency if NiAlphaProperty was present + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); + if (result.first) + { + alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ + alphaTest = result.second; + depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on + } + + if((alphaFlags&1)) + { + std::string blend_mode; + blend_mode += getBlendFactor((alphaFlags>>1)&0xf); + blend_mode += " "; + blend_mode += getBlendFactor((alphaFlags>>5)&0xf); + instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); + } + + if((alphaFlags>>9)&1) + { + std::string reject; + reject += getTestMode((alphaFlags>>10)&0x7); + reject += " "; + reject += Ogre::StringConverter::toString(alphaTest); + instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); + } + else + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); + + // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( + ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); + + instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); + // depth_func??? + + sh::Factory::getInstance()._ensureMaterial(name, "Default"); + return name; +} + +std::map NIFMaterialLoader::sMaterialMap; + +} diff --git a/components/nifogre/material.hpp b/components/nifogre/material.hpp new file mode 100644 index 0000000000..8843ac6c6c --- /dev/null +++ b/components/nifogre/material.hpp @@ -0,0 +1,57 @@ +#ifndef COMPONENTS_NIFOGRE_MATERIAL_HPP +#define COMPONENTS_NIFOGRE_MATERIAL_HPP + +#include +#include +#include +#include + +#include + +namespace Nif +{ + class ShapeData; + class NiTexturingProperty; + class NiMaterialProperty; + class NiAlphaProperty; + class NiVertexColorProperty; + class NiZBufferProperty; + class NiSpecularProperty; + class NiWireframeProperty; +} + +namespace NifOgre +{ + +class NIFMaterialLoader { + static void warn(const std::string &msg) + { + std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; + } + + static void fail(const std::string &msg) + { + std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; + abort(); + } + + static std::map sMaterialMap; + + static std::string findTextureName(const std::string &filename); + +public: + static Ogre::String getMaterial(const Nif::ShapeData *shapedata, + const Ogre::String &name, const Ogre::String &group, + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop, + const Nif::NiWireframeProperty *wireprop, + bool &needTangents); +}; + +} + +#endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 0a30f38bd1..3bd93a1b9f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -40,18 +40,11 @@ #include #include -#include -#include -#include - -#include - #include #include -#include -#include #include "skeleton.hpp" +#include "material.hpp" namespace std { @@ -424,404 +417,6 @@ public: }; -// Conversion of blend / test mode from NIF -static const char *getBlendFactor(int mode) -{ - switch(mode) - { - case 0: return "one"; - case 1: return "zero"; - case 2: return "src_colour"; - case 3: return "one_minus_src_colour"; - case 4: return "dest_colour"; - case 5: return "one_minus_dest_colour"; - case 6: return "src_alpha"; - case 7: return "one_minus_src_alpha"; - case 8: return "dest_alpha"; - case 9: return "one_minus_dest_alpha"; - case 10: return "src_alpha_saturate"; - } - std::cerr<< "Unexpected blend mode: "< MaterialMap; - -static void warn(const std::string &msg) -{ - std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; -} - -static void fail(const std::string &msg) -{ - std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; - abort(); -} - - -static std::string findTextureName(const std::string &filename) -{ - /* Bethesda 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. - */ - static const char path[] = "textures\\"; - static const char path2[] = "textures/"; - - - std::string texname = filename; - Misc::StringUtils::toLower(texname); - - if(texname.compare(0, sizeof(path)-1, path) != 0 - && texname.compare(0, sizeof(path2)-1, path2) != 0) - texname = path + texname; - - Ogre::String::size_type pos = texname.rfind('.'); - if(pos != Ogre::String::npos && texname.compare(pos, texname.length() - pos, ".dds") != 0) - { - // since we know all (GOTY edition or less) textures end - // in .dds, we change the extension - texname.replace(pos, texname.length(), ".dds"); - - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texname)) - { - texname = filename; - Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0 - && texname.compare(0, sizeof(path2)-1, path2) != 0) - texname = path + texname; - } - } - - return texname; -} - -public: -static Ogre::String getMaterial(const Nif::ShapeData *shapedata, - const Ogre::String &name, const Ogre::String &group, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop, - const Nif::NiWireframeProperty *wireprop, - bool &needTangents) -{ - 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 = 0; - int alphaTest = 0; - int vertMode = 2; - //int lightMode = 1; - int depthFlags = 3; - // Default should be 1, but Bloodmoon's models are broken - int specFlags = 0; - int wireFlags = 0; - Ogre::String texName[7]; - - bool vertexColour = (shapedata->colors.size() != 0); - - // Texture - if(texprop) - { - for(int i = 0;i < 7;i++) - { - if(!texprop->textures[i].inUse) - continue; - if(texprop->textures[i].texture.empty()) - { - warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); - continue; - } - - const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); - if(st->external) - texName[i] = findTextureName(st->filename); - else - warn("Found internal texture, ignoring."); - } - - Nif::ControllerPtr ctrls = texprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled texture controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); - - // Alpha modifiers - if(alphaprop) - { - alphaFlags = alphaprop->flags; - alphaTest = alphaprop->data.threshold; - - Nif::ControllerPtr ctrls = alphaprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled alpha controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Vertex color handling - if(vertprop) - { - vertMode = vertprop->data.vertmode; - // FIXME: Handle lightmode? - //lightMode = vertprop->data.lightmode; - - Nif::ControllerPtr ctrls = vertprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(zprop) - { - depthFlags = zprop->flags; - // Depth function??? - - Nif::ControllerPtr ctrls = zprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled depth controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(specprop) - { - specFlags = specprop->flags; - - Nif::ControllerPtr ctrls = specprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled specular controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(wireprop) - { - wireFlags = wireprop->flags; - - Nif::ControllerPtr ctrls = wireprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Material - if(matprop) - { - ambient = matprop->data.ambient; - diffuse = matprop->data.diffuse; - specular = matprop->data.specular; - emissive = matprop->data.emissive; - glossiness = matprop->data.glossiness; - alpha = matprop->data.alpha; - - Nif::ControllerPtr ctrls = matprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled material controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - { - // Generate a hash out of all properties that can affect the material. - size_t h = 0; - boost::hash_combine(h, ambient.x); - boost::hash_combine(h, ambient.y); - boost::hash_combine(h, ambient.z); - boost::hash_combine(h, diffuse.x); - boost::hash_combine(h, diffuse.y); - boost::hash_combine(h, diffuse.z); - boost::hash_combine(h, alpha); - boost::hash_combine(h, specular.x); - boost::hash_combine(h, specular.y); - boost::hash_combine(h, specular.z); - boost::hash_combine(h, glossiness); - boost::hash_combine(h, emissive.x); - boost::hash_combine(h, emissive.y); - boost::hash_combine(h, emissive.z); - for(int i = 0;i < 7;i++) - { - if(!texName[i].empty()) - boost::hash_combine(h, texName[i]); - } - boost::hash_combine(h, vertexColour); - boost::hash_combine(h, alphaFlags); - boost::hash_combine(h, alphaTest); - boost::hash_combine(h, vertMode); - boost::hash_combine(h, depthFlags); - boost::hash_combine(h, specFlags); - boost::hash_combine(h, wireFlags); - - std::map::iterator itr = MaterialMap.find(h); - if (itr != MaterialMap.end()) - { - // a suitable material exists already - use it - return itr->second; - } - // not found, create a new one - MaterialMap.insert(std::make_pair(h, name)); - } - - // No existing material like this. Create a new one. - sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); - if(vertMode == 0 || !vertexColour) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); - } - else if(vertMode == 1) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); - } - else if(vertMode == 2) - { - instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); - } - else - std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); - } - - if(wireFlags) - { - instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); - } - - instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); - instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); - instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); - if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) - { - instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); - } - if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) - { - instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); - } - if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) - { - // force automips on normal maps for now - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); - } - - for(int i = 0;i < 7;i++) - { - if(i == Nif::NiTexturingProperty::BaseTexture || - i == Nif::NiTexturingProperty::DetailTexture || - i == Nif::NiTexturingProperty::BumpTexture || - i == Nif::NiTexturingProperty::GlowTexture) - continue; - if(!texName[i].empty()) - warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); - } - - if (vertexColour) - instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); - - // Add transparency if NiAlphaProperty was present - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); - if (result.first) - { - alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ - alphaTest = result.second; - depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on - } - - if((alphaFlags&1)) - { - std::string blend_mode; - blend_mode += getBlendFactor((alphaFlags>>1)&0xf); - blend_mode += " "; - blend_mode += getBlendFactor((alphaFlags>>5)&0xf); - instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); - } - - if((alphaFlags>>9)&1) - { - std::string reject; - reject += getTestMode((alphaFlags>>10)&0x7); - reject += " "; - reject += Ogre::StringConverter::toString(alphaTest); - instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); - } - else - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - - // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( - ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); - - instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); - // depth_func??? - - sh::Factory::getInstance()._ensureMaterial(name, "Default"); - return name; -} - -}; -std::map NIFMaterialLoader::MaterialMap; - - /** Manual resource loader for NIF objects (meshes, particle systems, etc). * This is the main class responsible for translating the internal NIF * structures into something Ogre can use. From 6128b9276f35d75c6fccb5a05e458fc8537ac5bc Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Thu, 11 Apr 2013 00:21:56 -0400 Subject: [PATCH 1043/1483] Removed non-essential includes from all MWGui header files. --- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.hpp | 4 ---- apps/openmw/mwgui/container.hpp | 3 --- apps/openmw/mwgui/cursor.hpp | 1 - apps/openmw/mwgui/dialogue.hpp | 3 --- apps/openmw/mwgui/dialoguehistory.hpp | 1 + apps/openmw/mwgui/enchantingdialog.hpp | 2 -- apps/openmw/mwgui/hud.hpp | 2 -- apps/openmw/mwgui/itemselection.hpp | 2 -- apps/openmw/mwgui/journalwindow.hpp | 3 --- apps/openmw/mwgui/list.hpp | 1 - apps/openmw/mwgui/loadingscreen.hpp | 1 - apps/openmw/mwgui/messagebox.hpp | 2 -- apps/openmw/mwgui/quickkeysmenu.hpp | 1 - apps/openmw/mwgui/race.hpp | 5 ----- apps/openmw/mwgui/repair.hpp | 1 - apps/openmw/mwgui/review.hpp | 1 - apps/openmw/mwgui/statswindow.hpp | 5 ----- apps/openmw/mwgui/tradewindow.hpp | 3 --- apps/openmw/mwgui/travelwindow.hpp | 3 --- apps/openmw/mwgui/widgets.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ----- 22 files changed, 2 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index c61d2f92b3..655a832c17 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,12 +5,12 @@ #include "../mwmechanics/alchemy.hpp" -#include "windowbase.hpp" #include "container.hpp" #include "widgets.hpp" namespace MWGui { + class AlchemyWindow : public WindowBase, public ContainerBase { public: diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index fed77e889f..586faf966e 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -1,13 +1,9 @@ #ifndef CHARACTER_CREATION_HPP #define CHARACTER_CREATION_HPP -#include "../mwworld/esmstore.hpp" - #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/stat.hpp" - namespace MWGui { class WindowBase; diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 521ac8cc35..8440c6444e 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -1,13 +1,10 @@ #ifndef MGUI_CONTAINER_H #define MGUI_CONTAINER_H -#include "../mwworld/esmstore.hpp" - #include "windowbase.hpp" #include "referenceinterface.hpp" #include "../mwclass/container.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwgui/cursor.hpp b/apps/openmw/mwgui/cursor.hpp index 3a4a05f4ca..badf82262b 100644 --- a/apps/openmw/mwgui/cursor.hpp +++ b/apps/openmw/mwgui/cursor.hpp @@ -3,7 +3,6 @@ #include #include -#include namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a1bbee02c7..74fa8051c5 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -3,9 +3,6 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" -#include - -#include "../mwworld/ptr.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/dialoguehistory.hpp b/apps/openmw/mwgui/dialoguehistory.hpp index c37504af77..4cf6de621d 100644 --- a/apps/openmw/mwgui/dialoguehistory.hpp +++ b/apps/openmw/mwgui/dialoguehistory.hpp @@ -1,5 +1,6 @@ #ifndef MWGUI_DIALOGE_HISTORY_H #define MWGUI_DIALOGE_HISTORY_H + #include namespace MWGui diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index c727a09749..8bad60c8e6 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_ENCHANTINGDIALOG_H #define MWGUI_ENCHANTINGDIALOG_H -#include "windowbase.hpp" -#include "referenceinterface.hpp" #include "spellcreationdialog.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index c65566ce3e..1dd53683b8 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -1,7 +1,5 @@ #include "mapwindow.hpp" -#include - #include "../mwmechanics/stat.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 3e812d26c5..19007de6b0 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -1,7 +1,5 @@ #include "container.hpp" -#include "../mwworld/ptr.hpp" - namespace MWGui { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 7670b65f55..da05a6f0ec 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,10 +1,7 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H -#include -#include #include -#include #include "windowbase.hpp" #include "imagebutton.hpp" diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index 09e42e865e..956523c0dc 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -1,7 +1,6 @@ #ifndef MWGUI_LIST_HPP #define MWGUI_LIST_HPP -#include #include namespace MWGui diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 12e6504bca..87cedaa98c 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -2,7 +2,6 @@ #define MWGUI_LOADINGSCREEN_H #include -#include #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index cb40739023..0df6f3544b 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_MESSAGE_BOX_H #define MWGUI_MESSAGE_BOX_H -#include - #include "windowbase.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 646ec2aa45..058519ece4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -1,7 +1,6 @@ #ifndef MWGUI_QUICKKEYS_H #define MWGUI_QUICKKEYS_H - #include "../mwworld/ptr.hpp" #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index f3adce4447..893c4c90b6 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -1,11 +1,6 @@ #ifndef MWGUI_RACE_H #define MWGUI_RACE_H - -#include - -#include "../mwworld/esmstore.hpp" - #include "../mwrender/characterpreview.hpp" #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 5d9a487199..d0f5c54c4b 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -3,7 +3,6 @@ #include "windowbase.hpp" -#include "../mwworld/ptr.hpp" #include "../mwmechanics/repair.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index d5df94e285..87d6fedfa7 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -2,7 +2,6 @@ #define MWGUI_REVIEW_H #include "windowbase.hpp" -#include "../mwmechanics/stat.hpp" #include "widgets.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 4b723048cc..bec42d029b 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -3,11 +3,6 @@ #include "../mwworld/esmstore.hpp" -#include -#include -#include -#include - #include "../mwmechanics/stat.hpp" #include "windowpinnablebase.hpp" diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index e526a42ca5..892ce0297c 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -2,9 +2,6 @@ #define MWGUI_TRADEWINDOW_H #include "container.hpp" -#include "windowbase.hpp" - -#include "../mwworld/ptr.hpp" namespace MyGUI { diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index a814d04785..f2a23b0486 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -2,9 +2,6 @@ #define MWGUI_TravelWINDOW_H #include "container.hpp" -#include "windowbase.hpp" - -#include "../mwworld/ptr.hpp" namespace MyGUI { diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 038ce3f86f..1567946913 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -4,8 +4,6 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/stat.hpp" -#include -#include #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3c9fc586a3..652ad870f3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -10,11 +10,6 @@ this class. **/ -#include -#include - -#include - #include "../mwbase/windowmanager.hpp" namespace MyGUI From 62e0abd94582060951c887ac6a1782ea1644aa2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 22:38:46 -0700 Subject: [PATCH 1044/1483] Move the mesh loader to its own source file --- components/CMakeLists.txt | 2 +- components/nifogre/mesh.cpp | 375 +++++++++++++++++++ components/nifogre/mesh.hpp | 55 +++ components/nifogre/ogrenifloader.cpp | 526 +++++---------------------- 4 files changed, 516 insertions(+), 442 deletions(-) create mode 100644 components/nifogre/mesh.cpp create mode 100644 components/nifogre/mesh.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index aa422b49e7..dd8f78eda6 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader skeleton material + ogrenifloader skeleton material mesh ) add_component_dir (nifbullet diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp new file mode 100644 index 0000000000..3780306f6d --- /dev/null +++ b/components/nifogre/mesh.cpp @@ -0,0 +1,375 @@ +#include "mesh.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "material.hpp" + +namespace NifOgre +{ + +void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop); + +// Helper class that computes the bounding box and of a mesh +class BoundsFinder +{ + struct MaxMinFinder + { + float max, min; + + MaxMinFinder() + { + min = std::numeric_limits::infinity(); + max = -min; + } + + void add(float f) + { + if (f > max) max = f; + if (f < min) min = f; + } + + // Return Max(max**2, min**2) + float getMaxSquared() + { + float m1 = max*max; + float m2 = min*min; + if (m1 >= m2) return m1; + return m2; + } + }; + + MaxMinFinder X, Y, Z; + +public: + // Add 'verts' vertices to the calculation. The 'data' pointer is + // expected to point to 3*verts floats representing x,y,z for each + // point. + void add(float *data, int verts) + { + for (int i=0;idata.getPtr(); + const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); + std::vector srcVerts = data->vertices; + std::vector srcNorms = data->normals; + Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; + bool vertShadowBuffer = false; + if(skin != NULL) + { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + + // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be + // 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); + + // 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(0.0f)); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) + { + Ogre::Bone *bone = skel->getBone(bones[b]->name); + Ogre::Matrix4 mat; + mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), + Ogre::Quaternion(data->bones[b].trafo.rotation)); + mat = bone->_getFullTransform() * mat; + + const std::vector &weights = data->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) + { + size_t index = weights[i].vertex; + float weight = weights[i].weight; + + newVerts.at(index) += (mat*srcVerts[index]) * weight; + if(newNorms.size() > index) + { + Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); + vec4 = mat*vec4 * weight; + newNorms[index] += Ogre::Vector3(&vec4[0]); + } + } + } + + srcVerts = newVerts; + srcNorms = newNorms; + } + else + { + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(skelMgr->getByName(mName).isNull()) + { + // 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()); + if(!bounds.isValid()) + { + float v[3] = { 0.0f, 0.0f, 0.0f }; + bounds.add(&v[0], 1); + } + + 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 + // 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(); + + // 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(), vertUsage, vertShadowBuffer); + 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(), vertUsage, vertShadowBuffer); + 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); + 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(); + for(size_t i = 0;i < numUVs;i++) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), + srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); + vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + + decl->addElement(nextBuf, 0, 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); + 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(skin != NULL) + { + 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]->name)->getHandle(); + + const std::vector &weights = data->bones[i].weights; + for(size_t j = 0;j < weights.size();j++) + { + boneInf.vertexIndex = weights[j].vertex; + boneInf.weight = weights[j].weight; + sub->addBoneAssignment(boneInf); + } + } + } + + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; + bool needTangents = false; + + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + wireprop, needTangents); + if(matname.length() > 0) + sub->setMaterialName(matname); + + // build tangents if the material needs them + if (needTangents) + { + unsigned short src,dest; + if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) + mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); + } +} + + +NIFMeshLoader::NIFMeshLoader(const std::string &name, const std::string &group, size_t idx) + : mName(name), mGroup(group), mShapeIndex(idx) +{ +} + +void NIFMeshLoader::loadResource(Ogre::Resource *resource) +{ + Ogre::Mesh *mesh = dynamic_cast(resource); + OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); + + Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); + if(mShapeIndex >= nif->numRecords()) + { + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(!skelMgr->getByName(mName).isNull()) + mesh->setSkeletonName(mName); + return; + } + + const Nif::Record *record = nif->getRecord(mShapeIndex); + createSubMesh(mesh, dynamic_cast(record)); +} + + +void NIFMeshLoader::createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx) +{ + NIFMeshLoader::LoaderMap::iterator loader; + loader = sLoaders.insert(std::make_pair(fullname, NIFMeshLoader(name, group, idx))).first; + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + Ogre::MeshPtr mesh = meshMgr.createManual(fullname, group, &loader->second); + mesh->setAutoBuildEdgeLists(false); +} + +} diff --git a/components/nifogre/mesh.hpp b/components/nifogre/mesh.hpp new file mode 100644 index 0000000000..731e49c903 --- /dev/null +++ b/components/nifogre/mesh.hpp @@ -0,0 +1,55 @@ +#ifndef COMPONENTS_NIFOGRE_MESH_HPP +#define COMPONENTS_NIFOGRE_MESH_HPP + +#include +#include +#include +#include + +#include + +namespace Nif +{ + class NiTriShape; +} + +namespace NifOgre +{ + +/** Manual resource loader for NiTriShapes. This is the main class responsible + * for translating the internal NIF meshes into something Ogre can use. + */ +class NIFMeshLoader : Ogre::ManualResourceLoader +{ + 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(); + } + + std::string mName; + std::string mGroup; + size_t mShapeIndex; + + // Convert NiTriShape to Ogre::SubMesh + void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape); + + typedef std::map LoaderMap; + static LoaderMap sLoaders; + + NIFMeshLoader(const std::string &name, const std::string &group, size_t idx); + + virtual void loadResource(Ogre::Resource *resource); + +public: + static void createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx); +}; + +} + +#endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3bd93a1b9f..8d82c3ced7 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -25,12 +25,7 @@ #include -#include -#include -#include -#include #include -#include #include #include #include @@ -38,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -45,6 +42,7 @@ #include "skeleton.hpp" #include "material.hpp" +#include "mesh.hpp" namespace std { @@ -58,6 +56,46 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { +void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop) +{ + if(node->parent) + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + + const Nif::PropertyList &proplist = node->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); + else + std::cerr<< "Unhandled property type: "<recName < { @@ -332,101 +370,13 @@ public: }; -// Helper class that computes the bounding box and of a mesh -class BoundsFinder -{ - struct MaxMinFinder - { - float max, min; - - MaxMinFinder() - { - min = std::numeric_limits::infinity(); - max = -min; - } - - void add(float f) - { - if (f > max) max = f; - if (f < min) min = f; - } - - // Return Max(max**2, min**2) - float getMaxSquared() - { - float m1 = max*max; - float m2 = min*min; - if (m1 >= m2) return m1; - return m2; - } - }; - - MaxMinFinder X, Y, Z; - -public: - // Add 'verts' vertices to the calculation. The 'data' pointer is - // expected to point to 3*verts floats representing x,y,z for each - // point. - void add(float *data, int verts) - { - for (int i=0;iparent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - } - - // Convert NiTriShape to Ogre::SubMesh - void createSubMesh(Ogre::Mesh *mesh, const 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; - std::vector srcNorms = data->normals; - Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; - bool vertShadowBuffer = false; - if(skin != NULL) - { - vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; - vertShadowBuffer = true; - - // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be - // 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); - - // 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(0.0f)); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) - { - Ogre::Bone *bone = skel->getBone(bones[b]->name); - Ogre::Matrix4 mat; - mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), - Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bone->_getFullTransform() * mat; - - const std::vector &weights = data->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) - { - size_t index = weights[i].vertex; - float weight = weights[i].weight; - - newVerts.at(index) += (mat*srcVerts[index]) * weight; - if(newNorms.size() > index) - { - Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); - vec4 = mat*vec4 * weight; - newNorms[index] += Ogre::Vector3(&vec4[0]); - } - } - } - - srcVerts = newVerts; - srcNorms = newNorms; - } - else - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(skelMgr->getByName(mName).isNull()) - { - // 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()); - if(!bounds.isValid()) - { - float v[3] = { 0.0f, 0.0f, 0.0f }; - bounds.add(&v[0], 1); - } - - 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 - // 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(); - - // 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(), vertUsage, vertShadowBuffer); - 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(), vertUsage, vertShadowBuffer); - 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); - 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(); - for(size_t i = 0;i < numUVs;i++) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); - - decl->addElement(nextBuf, 0, 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); - 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(skin != NULL) - { - 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]->name)->getHandle(); - - const std::vector &weights = data->bones[i].weights; - for(size_t j = 0;j < weights.size();j++) - { - boneInf.vertexIndex = weights[j].vertex; - boneInf.weight = weights[j].weight; - sub->addBoneAssignment(boneInf); - } - } - } - - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - bool needTangents = false; - - getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, needTangents); - if(matname.length() > 0) - sub->setMaterialName(matname); - - // build tangents if the material needs them - if (needTangents) - { - unsigned short src,dest; - if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) - mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); - } - } - - - typedef std::map LoaderMap; - static LoaderMap sLoaders; - static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { @@ -743,8 +428,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } } - Ogre::ParticleSystem *createParticleSystem(Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, - const Nif::Node *partnode) + static Ogre::ParticleSystem *createParticleSystem(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, + const Nif::Node *partnode) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -754,7 +440,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); try { - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); if(partnode->name.length() > 0) fullname += "@type="+partnode->name; Misc::StringUtils::toLower(fullname); @@ -769,7 +455,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader bool needTangents = false; getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, needTangents)); @@ -789,7 +475,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader createParticleEmitterAffectors(partsys, partctrl); if(!partctrl->emitter.empty() && !partsys->isAttached()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partctrl->emitter->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); entitybase->attachObjectToBone(trgtbone->getName(), partsys); } @@ -799,7 +485,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(!partsys->isAttached()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partnode->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); entitybase->attachObjectToBone(trgtbone->getName(), partsys); } @@ -813,29 +499,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } - NIFObjectLoader(const std::string &name, const std::string &group) - : mName(name), mGroup(group), mShapeIndex(~(size_t)0) - { } - - virtual void loadResource(Ogre::Resource *resource) - { - Ogre::Mesh *mesh = dynamic_cast(resource); - OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); - - Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); - if(mShapeIndex >= nif->numRecords()) - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(!skelMgr->getByName(mName).isNull()) - mesh->setSkeletonName(mName); - return; - } - - const Nif::Record *record = nif->getRecord(mShapeIndex); - createSubMesh(mesh, dynamic_cast(record)); - } - - void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags=0) + static void createObjects(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, const Nif::Node *node, + ObjectList &objectlist, int flags=0) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -868,7 +534,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiCamera) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, node->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mCameras.push_back(trgtbone); } @@ -880,7 +546,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader { const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::ControllerValueRealPtr srcval; /* Filled in later */ Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); @@ -893,7 +559,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); if(!key->data.empty()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::ControllerValueRealPtr srcval; /* Filled in later */ Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); @@ -909,24 +575,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader { const Nif::NiTriShape *shape = static_cast(node); - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); if(shape->name.length() > 0) fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - Ogre::MeshPtr mesh = meshMgr.getByName(fullname); - if(mesh.isNull()) - { - NIFObjectLoader *loader = &sLoaders[fullname]; - *loader = *this; - loader->mShapeIndex = shape->recIndex; - mesh = meshMgr.createManual(fullname, mGroup, loader); - mesh->setAutoBuildEdgeLists(false); - } + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + if(meshMgr.getByName(fullname).isNull()) + NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - Ogre::Entity *entity = sceneMgr->createEntity(mesh); + Ogre::Entity *entity = sceneMgr->createEntity(fullname); entity->setVisible(!(flags&0x01)); objectlist.mEntities.push_back(entity); @@ -936,7 +594,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader entity->shareSkeletonInstanceWith(objectlist.mSkelBase); else { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } @@ -963,7 +621,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) { - Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, objectlist.mSkelBase, node); + Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) { partsys->setVisible(!(flags&0x01)); @@ -978,71 +636,57 @@ class NIFObjectLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(sceneMgr, children[i].getPtr(), objectlist, flags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags); } } } - void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist) + static void createSkelBase(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, const Nif::Node *node, + ObjectList &objectlist) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all * other meshes are hidden or entities attached to a specific node * instead of skinned. */ - std::string fullname = mName; - Misc::StringUtils::toLower(fullname); - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - Ogre::MeshPtr mesh = meshMgr.getByName(fullname); - if(mesh.isNull()) - { - NIFObjectLoader *loader = &sLoaders[fullname]; - *loader = *this; + if(meshMgr.getByName(name).isNull()) + NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); - mesh = meshMgr.createManual(fullname, mGroup, loader); - mesh->setAutoBuildEdgeLists(false); - } - objectlist.mSkelBase = sceneMgr->createEntity(mesh); + objectlist.mSkelBase = sceneMgr->createEntity(name); objectlist.mEntities.push_back(objectlist.mSkelBase); } public: - NIFObjectLoader() : mShapeIndex(~(size_t)0) - { } - static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) { - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRoots() < 1) + Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); + if(nif->numRoots() < 1) { - nif.warn("Found no root nodes in "+name+"."); + nif->warn("Found no root nodes in "+name+"."); return; } - // The first record is assumed to be the root node - const Nif::Record *r = nif.getRoot(0); + const Nif::Record *r = nif->getRoot(0); assert(r != NULL); - const Nif::Node *node = dynamic_cast(r); + const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First root in "+name+" was not a node, but a "+ - r->recName+"."); + nif->warn("First root in "+name+" was not a node, but a "+ + r->recName+"."); return; } - bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); - if(!hasSkel) - hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - - NIFObjectLoader meshldr(name, group); - if(hasSkel) - meshldr.createSkelBase(sceneMgr, node, objectlist); - meshldr.createObjects(sceneMgr, node, objectlist); + if(Ogre::SkeletonManager::getSingleton().resourceExists(name) || + !NIFSkeletonLoader::createSkeleton(name, group, node).isNull()) + { + // Create a base skeleton entity if this NIF needs one + createSkelBase(name, group, sceneMgr, node, objectlist); + } + createObjects(name, group, sceneMgr, node, objectlist); } }; -NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; ObjectList Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) From d26ffe9de02dfd69a7477eae31349c6a9efbca94 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 23:19:47 -0700 Subject: [PATCH 1045/1483] Move a method to the Node class --- components/nif/niffile.cpp | 38 +++++++++++++++++++++++++ components/nif/node.hpp | 8 ++++++ components/nifogre/mesh.cpp | 11 +------- components/nifogre/ogrenifloader.cpp | 42 +--------------------------- 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 44eae2953d..3b41e96a70 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -384,6 +384,44 @@ void NiSkinInstance::post(NIFFile *nif) } } + +void Node::getProperties(const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop) const +{ + if(parent) + parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + + for(size_t i = 0;i < props.length();i++) + { + // Entries may be empty + if(props[i].empty()) + continue; + + const Nif::Property *pr = props[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); + else + std::cerr<< "Unhandled property type: "<recName <getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8d82c3ced7..48893bf4a8 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -56,46 +56,6 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { -void getNodeProperties(const Nif::Node *node, - const Nif::NiTexturingProperty *&texprop, - const Nif::NiMaterialProperty *&matprop, - const Nif::NiAlphaProperty *&alphaprop, - const Nif::NiVertexColorProperty *&vertprop, - const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop) -{ - if(node->parent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else - std::cerr<< "Unhandled property type: "<recName < { @@ -454,7 +414,7 @@ class NIFObjectLoader const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, texprop, matprop, alphaprop, vertprop, zprop, specprop, From 6d3a2cd5a0c5364395cdad5aeedb291abeffc1e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 10:50:22 +0200 Subject: [PATCH 1046/1483] added comment token (for use in syntax colouring) --- components/compiler/parser.cpp | 5 +++++ components/compiler/parser.hpp | 7 +++++++ components/compiler/scanner.cpp | 9 ++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 896458e482..8d11c4086d 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -148,6 +148,11 @@ namespace Compiler return false; } + bool Parser::parseComment (const std::string& comment, const TokenLoc& loc, Scanner& scanner) + { + return true; + } + // Handle an EOF token. // // - Default-implementation: Report an error. diff --git a/components/compiler/parser.hpp b/components/compiler/parser.hpp index 221e7c2c9f..4fec570e9f 100644 --- a/components/compiler/parser.hpp +++ b/components/compiler/parser.hpp @@ -82,6 +82,13 @@ namespace Compiler /// /// - Default-implementation: Report an error. + virtual bool parseComment (const std::string& comment, const TokenLoc& loc, + Scanner& scanner); + ///< Handle comment token. + /// \return fetch another token? + /// + /// - Default-implementation: ignored (and return true). + virtual void parseEOF (Scanner& scanner); ///< Handle EOF token. /// diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 420fd8f7f3..38a9265a1e 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -88,6 +88,10 @@ namespace Compiler } else if (c==';') { + std::string comment; + + comment += c; + while (get (c)) { if (c=='\n') @@ -95,11 +99,14 @@ namespace Compiler putback (c); break; } + else + comment += c; } + TokenLoc loc (mLoc); mLoc.mLiteral.clear(); - return true; + return parser.parseComment (comment, loc, *this); } else if (isWhitespace (c)) { From f17cebde0aea9e8cc1aaedd3592923eb5618c0fb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 10:50:35 +0200 Subject: [PATCH 1047/1483] syntax colouring for comments --- apps/opencs/view/world/scripthighlighter.cpp | 15 ++++++++++++++- apps/opencs/view/world/scripthighlighter.hpp | 7 +++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 1e93ac26b7..288a3d12ac 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -40,6 +40,13 @@ bool CSVWorld::ScriptHighlighter::parseSpecial (int code, const Compiler::TokenL return true; } +bool CSVWorld::ScriptHighlighter::parseComment (const std::string& comment, + const Compiler::TokenLoc& loc, Compiler::Scanner& scanner) +{ + highlight (loc, Type_Comment); + return true; +} + void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner) {} @@ -67,7 +74,7 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) { QTextCharFormat format; - format.setForeground (Qt::green); + format.setForeground (Qt::magenta); mScheme.insert (std::make_pair (Type_Float, format)); } @@ -88,6 +95,12 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) format.setForeground (Qt::darkYellow); mScheme.insert (std::make_pair (Type_Special, format)); } + + { + QTextCharFormat format; + format.setForeground (Qt::green); + mScheme.insert (std::make_pair (Type_Comment, format)); + } } void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp index e9918f99b7..3ef6978097 100644 --- a/apps/opencs/view/world/scripthighlighter.hpp +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -22,7 +22,8 @@ namespace CSVWorld Type_Float, Type_Name, Type_Keyword, - Type_Special + Type_Special, + Type_Comment }; private: @@ -58,7 +59,9 @@ namespace CSVWorld ///< Handle a special character token. /// \return fetch another token? - ///< Handle a special character token. + virtual bool parseComment (const std::string& comment, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle comment token. /// \return fetch another token? virtual void parseEOF (Compiler::Scanner& scanner); From 9c7ad758169c0a539b629540e3123348060505b2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 14:44:02 +0200 Subject: [PATCH 1048/1483] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index f06377500a..6456e30a10 100644 --- a/credits.txt +++ b/credits.txt @@ -16,6 +16,7 @@ Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) athile +Britt Mathis (galdor557) BrotherBrick Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) From 2c70074dd745b083cdc99f38fff89e5e5f0776b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Apr 2013 20:25:03 +0200 Subject: [PATCH 1049/1483] Fix combinedAlpha --- files/materials/terrain.shader | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index de90a6cf61..58146118e9 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -227,7 +227,8 @@ #if !IS_FIRST_PASS -float combinedAlpha = 0.f; +// Opacity the previous passes should have, i.e. 1 - (opacity of this pass) +float previousAlpha = 1.f; #endif // Layer calculations @@ -252,7 +253,7 @@ float combinedAlpha = 0.f; #else albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); #endif - combinedAlpha += blendValues@shPropertyString(blendmap_component_@shIterator); + previousAlpha *= 1.f-blendValues@shPropertyString(blendmap_component_@shIterator); #endif @shEndForeach @@ -344,7 +345,7 @@ float combinedAlpha = 0.f; #if IS_FIRST_PASS shOutputColour(0).a = 1; #else - shOutputColour(0).a = min(combinedAlpha, 1.f); + shOutputColour(0).a = 1.f-previousAlpha; #endif } From b98063bba03473d9dc0a7e0c3953069eb1a26ee9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Apr 2013 18:02:44 +0200 Subject: [PATCH 1050/1483] Fix deleted pointer access (getPosition, getRotation) --- libs/openengine/bullet/physic.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index f71fa4320b..524f57c1c4 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -19,7 +19,7 @@ namespace Physic PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) - , mBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) + , mBody(0), mRaycastingBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) { // FIXME: Force player to start in no-collision mode for now, until he spawns at a proper door marker. if(name == "player") @@ -47,6 +47,7 @@ namespace Physic void PhysicActor::enableCollisions(bool collision) { + assert(mBody); if(collision && !collisionMode) mBody->translate(btVector3(0,0,-1000)); if(!collision && collisionMode) mBody->translate(btVector3(0,0,1000)); collisionMode = collision; @@ -55,6 +56,7 @@ namespace Physic void PhysicActor::setPosition(const Ogre::Vector3 &pos) { + assert(mBody); if(pos != getPosition()) { mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); @@ -64,6 +66,7 @@ namespace Physic void PhysicActor::setRotation(const Ogre::Quaternion &quat) { + assert(mBody); if(!quat.equals(getRotation(), Ogre::Radian(0))){ mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); mEngine->adjustRigidBody(mRaycastingBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); @@ -74,6 +77,7 @@ namespace Physic Ogre::Vector3 PhysicActor::getPosition() { + assert(mBody); btVector3 vec = mBody->getWorldTransform().getOrigin(); Ogre::Quaternion rotation = Ogre::Quaternion(mBody->getWorldTransform().getRotation().getW(), mBody->getWorldTransform().getRotation().getX(), mBody->getWorldTransform().getRotation().getY(), mBody->getWorldTransform().getRotation().getZ()); @@ -84,14 +88,18 @@ namespace Physic Ogre::Quaternion PhysicActor::getRotation() { + assert(mBody); btQuaternion quat = mBody->getWorldTransform().getRotation() * mBoxRotationInverse; return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()); } void PhysicActor::setScale(float scale){ //We only need to change the scaled box translation, box rotations remain the same. + assert(mBody); mBoxScaledTranslation = mBoxScaledTranslation / mBody->getCollisionShape()->getLocalScaling().getX(); mBoxScaledTranslation *= scale; + Ogre::Vector3 pos = getPosition(); + Ogre::Quaternion rot = getRotation(); if(mBody){ mEngine->dynamicsWorld->removeRigidBody(mBody); mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody); @@ -99,8 +107,8 @@ namespace Physic delete mRaycastingBody; } //Create the newly scaled rigid body - mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation()); - mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation(), 0, 0, true); + mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot); + mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot, 0, 0, true); mEngine->addRigidBody(mBody, false, mRaycastingBody); //Add rigid body to dynamics world, but do not add to object map } From 6934b20abd7c09ece9469f2be330512d91895982 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 17:57:58 +0100 Subject: [PATCH 1051/1483] actors are now updates every frame. This should not be the case, but this is a quickfix for AI. --- apps/openmw/mwmechanics/actors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 89671ee086..82e46ea463 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -210,7 +210,7 @@ namespace MWMechanics { mDuration += duration; - if (mDuration>=0.25) + //if (mDuration>=0.25) { float totalDuration = mDuration; mDuration = 0; From 0a187e56aa8331624163789059dee3ca85a25095 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 17:58:11 +0100 Subject: [PATCH 1052/1483] bugfix --- apps/openmw/mwmechanics/aitravel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 25efe8fff0..65d43749bc 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -80,9 +80,9 @@ namespace MWMechanics dest.mZ = mZ; ESM::Pathgrid::Point start; - dest.mX = pos.pos[0]; - dest.mY = pos.pos[1]; - dest.mZ = pos.pos[2]; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } From 905cff2a9456406f1be91ca311ab219980e9840c Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 18:02:12 +0100 Subject: [PATCH 1053/1483] anonymous namespace --- apps/openmw/mwmechanics/aitravel.cpp | 15 +++++++++------ apps/openmw/mwmechanics/pathfinding.cpp | 8 +++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 65d43749bc..13ae2a592e 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,6 +13,15 @@ #include #include "boost/tuple/tuple.hpp" +namespace +{ + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } +} + namespace MWMechanics { @@ -26,12 +35,6 @@ namespace MWMechanics return new AiTravel(*this); } - static float sgn(float a) - { - if(a>0) return 1.; - else return -1.; - } - bool AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1d98674ef5..7c22e54701 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -4,10 +4,9 @@ #include "boost/tuple/tuple.hpp" #include "OgreMath.h" -namespace MWMechanics +namespace { - - //helpers functions + //helpers functions float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); @@ -89,7 +88,10 @@ namespace MWMechanics const PathGridGraph & mGraph; PointID mGoal; }; +} +namespace MWMechanics +{ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; From 23b477a9380c4c6a4f60a2b809ba17a6aa9dc884 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Apr 2013 04:36:28 +0200 Subject: [PATCH 1054/1483] Fix normal maps with spaces in filename not getting loaded --- components/nifogre/material.cpp | 5 ----- extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp | 9 +++++++++ files/materials/objects.mat | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp index 431b8219a9..55f064c555 100644 --- a/components/nifogre/material.cpp +++ b/components/nifogre/material.cpp @@ -333,11 +333,6 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); } - if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) - { - // force automips on normal maps for now - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); - } for(int i = 0;i < 7;i++) { diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp index 4ec43fcaeb..f45e641557 100644 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp @@ -2,6 +2,8 @@ #include +#include + namespace sh { void OgreMaterialSerializer::reset() @@ -44,6 +46,13 @@ namespace sh bool OgreMaterialSerializer::setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t) { + // quick access to automip setting, without having to use 'texture' which doesn't like spaces in filenames + if (param == "num_mipmaps") + { + t->setNumMipmaps(Ogre::StringConverter::parseInt(value)); + return true; + } + reset(); mScriptContext.section = Ogre::MSS_TEXTUREUNIT; diff --git a/files/materials/objects.mat b/files/materials/objects.mat index b9277914bd..8f8734d629 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -55,7 +55,9 @@ material openmw_objects_base texture_unit normalMap { - texture $normalMap + direct_texture $normalMap + // force automips here for now + num_mipmaps 4 } texture_unit emissiveMap From a1ece7de306091c5b7beb834c49b9e34809cae3a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 12 Apr 2013 14:48:53 +0200 Subject: [PATCH 1055/1483] Bug #613: fixed assert in string literal access function --- components/interpreter/runtime.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index dcf17d2558..8814ca7ffc 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -34,17 +34,20 @@ namespace Interpreter std::string Runtime::getStringLiteral (int index) const { - assert (index>=0 && index (mCode[3])); + assert (index>=0 && static_cast (mCode[3])>0); const char *literalBlock = reinterpret_cast (mCode + 4 + mCode[0] + mCode[1] + mCode[2]); + int offset = 0; + for (; index; --index) { - literalBlock += std::strlen (literalBlock) + 1; + offset += std::strlen (literalBlock+offset) + 1; + assert (offset/4 (mCode[3])); } - return literalBlock; + return literalBlock+offset; } void Runtime::configure (const Interpreter::Type_Code *code, int codeSize, Context& context) From 5b30677e41f26312a6eb844c65c6169967815471 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Apr 2013 14:37:16 -0700 Subject: [PATCH 1056/1483] Add the start of a custom gravity affector --- components/nifogre/ogrenifloader.cpp | 15 ++- libs/openengine/ogre/particles.cpp | 181 +++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 11 ++ libs/openengine/ogre/renderer.cpp | 4 + 4 files changed, 207 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 48893bf4a8..113fd3d162 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -366,10 +366,21 @@ class NIFObjectLoader if(e->recType == Nif::RC_NiParticleGrowFade) { const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade"); affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } + else if(e->recType == Nif::RC_NiGravity) + { + const Nif::NiGravity *gr = static_cast(e.getPtr()); + + Ogre::ParticleAffector *affector = partsys->addAffector("Gravity"); + affector->setParameter("force", Ogre::StringConverter::toString(gr->mForce)); + affector->setParameter("force_type", (gr->mType==0) ? "wind" : "point"); + affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection)); + affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition)); + } else if(e->recType == Nif::RC_NiParticleRotation) { // TODO: Implement (Ogre::RotationAffector?) @@ -378,10 +389,6 @@ class NIFObjectLoader { // TODO: Implement (Ogre::ColourInterpolatorAffector?) } - else if(e->recType == Nif::RC_NiGravity) - { - // TODO: Implement - } else warn("Unhandled particle modifier "+e->recName); e = e->extra; diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 3453b7f3d7..244ca0ec3b 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -144,3 +144,184 @@ Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSy mAffectors.push_back(p); return p; } + + +class GravityAffector : public Ogre::ParticleAffector +{ + enum ForceType { + Type_Wind, + Type_Point + }; + +public: + /** Command object for force (see Ogre::ParamCommand).*/ + class CmdForce : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getForce()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setForce(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for force_type (see Ogre::ParamCommand).*/ + class CmdForceType : public Ogre::ParamCommand + { + static ForceType getTypeFromString(const Ogre::String &type) + { + if(type == "wind") + return Type_Wind; + if(type == "point") + return Type_Point; + OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type string: "+type, + "CmdForceType::getTypeFromString"); + } + + static Ogre::String getStringFromType(ForceType type) + { + switch(type) + { + case Type_Wind: return "wind"; + case Type_Point: return "point"; + } + OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type enum: "+Ogre::StringConverter::toString(type), + "CmdForceType::getStringFromType"); + } + + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return getStringFromType(self->getForceType()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setForceType(getTypeFromString(val)); + } + }; + + /** Command object for direction (see Ogre::ParamCommand).*/ + class CmdDirection : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getDirection()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setDirection(Ogre::StringConverter::parseVector3(val)); + } + }; + + /** Command object for position (see Ogre::ParamCommand).*/ + class CmdPosition : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getPosition()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setPosition(Ogre::StringConverter::parseVector3(val)); + } + }; + + + /** Default constructor. */ + GravityAffector(Ogre::ParticleSystem *psys) + : ParticleAffector(psys) + , mForce(0.0f) + , mForceType(Type_Wind) + , mPosition(0.0f) + , mDirection(0.0f) + { + mType = "Gravity"; + + // Init parameters + if(createParamDictionary("GravityAffector")) + { + Ogre::ParamDictionary *dict = getParamDictionary(); + + Ogre::String force_title("force"); + Ogre::String force_descr("Amount of force applied to particles."); + Ogre::String force_type_title("force_type"); + Ogre::String force_type_descr("Type of force applied to particles (point or wind)."); + Ogre::String direction_title("direction"); + Ogre::String direction_descr("Direction of wind forces."); + Ogre::String position_title("position"); + Ogre::String position_descr("Position of point forces."); + + dict->addParameter(Ogre::ParameterDef(force_title, force_descr, Ogre::PT_REAL), &msForceCmd); + dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd); + dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd); + dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd); + } + } + + /** See Ogre::ParticleAffector. */ + void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + } + } + + void setForce(Ogre::Real force) + { mForce = force; } + Ogre::Real getForce() const + { return mForce; } + + void setForceType(ForceType type) + { mForceType = type; } + ForceType getForceType() const + { return mForceType; } + + void setDirection(const Ogre::Vector3 &dir) + { mDirection = dir; } + const Ogre::Vector3 &getDirection() const + { return mDirection; } + + void setPosition(const Ogre::Vector3 &pos) + { mPosition = pos; } + const Ogre::Vector3 &getPosition() const + { return mPosition; } + + static CmdForce msForceCmd; + static CmdForceType msForceTypeCmd; + static CmdDirection msDirectionCmd; + static CmdPosition msPositionCmd; + +protected: + float mForce; + + ForceType mForceType; + + Ogre::Vector3 mPosition; + Ogre::Vector3 mDirection; +}; +GravityAffector::CmdForce GravityAffector::msForceCmd; +GravityAffector::CmdForceType GravityAffector::msForceTypeCmd; +GravityAffector::CmdDirection GravityAffector::msDirectionCmd; +GravityAffector::CmdPosition GravityAffector::msPositionCmd; + +Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleAffector *p = new GravityAffector(psys); + mAffectors.push_back(p); + return p; +} diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp index d466bb0308..0d88a348e3 100644 --- a/libs/openengine/ogre/particles.hpp +++ b/libs/openengine/ogre/particles.hpp @@ -14,4 +14,15 @@ class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); }; +/** Factory class for GravityAffector. */ +class GravityAffectorFactory : public Ogre::ParticleAffectorFactory +{ + /** See Ogre::ParticleAffectorFactory */ + Ogre::String getName() const + { return "Gravity"; } + + /** See Ogre::ParticleAffectorFactory */ + Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); +}; + #endif /* OENGINE_OGRE_PARTICLES_H */ diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index c9e91968f5..fcc4961b50 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -211,6 +211,10 @@ void OgreRenderer::configure(const std::string &logPath, Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); mAffectorFactories.push_back(affector); + affector = OGRE_NEW GravityAffectorFactory(); + Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); + mAffectorFactories.push_back(affector); + RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) From 86bac7aa9201ac54b71de4d76b150d1a95695daf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Apr 2013 23:40:30 +0200 Subject: [PATCH 1057/1483] Fix wrong BSA group name typo --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 17610e479f..118932ade6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -176,7 +176,7 @@ void OMW::Engine::loadBSA() if (mFileCollections.doesExist(*archive)) { // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(dataDirs.size()-i); + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); From 2eb9395661d84bb56603472564b79a0d9a054222 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Apr 2013 00:05:31 +0200 Subject: [PATCH 1058/1483] Do some padding with zeros on the resource group name to avoid priority problems with more than 10 resource groups. --- apps/openmw/engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 118932ade6..69e3cdc534 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -161,7 +161,7 @@ void OMW::Engine::loadBSA() for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { // Last data dir has the highest priority - std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i); + std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0'); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); std::string dataDirectory = iter->string(); @@ -176,7 +176,7 @@ void OMW::Engine::loadBSA() if (mFileCollections.doesExist(*archive)) { // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i); + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i, 8, '0'); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); From d50150ad715d278b42ec2201a0ad7728649db748 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Apr 2013 00:13:56 +0200 Subject: [PATCH 1059/1483] Scale adjustment factor should not be written back to cellref scale --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 11ccd8f2fc..e70aedd552 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -801,8 +801,8 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { - MWWorld::Class::get(ptr).adjustScale(ptr,scale); ptr.getCellRef().mScale = scale; + MWWorld::Class::get(ptr).adjustScale(ptr,scale); if(ptr.getRefData().getBaseNode() == 0) return; From 9cc97b195c1732bd784833452c49baee829b2c8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 13:03:45 -0700 Subject: [PATCH 1060/1483] Implement Gravity particle affector effects --- libs/openengine/ogre/particles.cpp | 34 +++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 244ca0ec3b..61ebddc562 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -274,10 +274,14 @@ public: /** See Ogre::ParticleAffector. */ void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) { - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) + switch(mForceType) { - Ogre::Particle *p = pi.getNext(); + case Type_Wind: + applyWindForce(psys, timeElapsed); + break; + case Type_Point: + applyPointForce(psys, timeElapsed); + break; } } @@ -307,6 +311,30 @@ public: static CmdPosition msPositionCmd; protected: + void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + const Ogre::Vector3 vec = mDirection * mForce * timeElapsed; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + p->direction += vec; + } + } + + void applyPointForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + const Ogre::Real force = mForce * timeElapsed; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + const Ogre::Vector3 vec = (p->position - mPosition).normalisedCopy() * force; + p->direction += vec; + } + } + + float mForce; ForceType mForceType; From 07c24e038212d6b1b3eb52838f9af690b4fa4c00 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 13:13:09 -0700 Subject: [PATCH 1061/1483] Don't create entities and particles when only the skeleton base is needed --- components/nifogre/ogrenifloader.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 113fd3d162..4e6d3b3c45 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -468,7 +468,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags=0) + ObjectList &objectlist, int flags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -585,8 +585,8 @@ class NIFObjectLoader } } - if(node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles) + if((node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) @@ -614,8 +614,7 @@ class NIFObjectLoader { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all - * other meshes are hidden or entities attached to a specific node - * instead of skinned. */ + * other entities are attached to bones and not skinned. */ Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); if(meshMgr.getByName(name).isNull()) NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); @@ -625,7 +624,7 @@ class NIFObjectLoader } public: - static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) + static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group, int flags=0) { Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); if(nif->numRoots() < 1) @@ -651,7 +650,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist); + createObjects(name, group, sceneMgr, node, objectlist, flags); } }; @@ -739,7 +738,7 @@ ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string na ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(sceneMgr, objectlist, name, group); + NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000); return objectlist; } From 7191f6ed2a7f500b1d51275d8ece011ed9590f8c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 14:36:24 -0700 Subject: [PATCH 1062/1483] Start a Nif-style particle emitter Not complete yet (doesn't handle the vertical or horizontal direction/angle), and should probably be renamed. --- components/nifogre/ogrenifloader.cpp | 5 +- libs/openengine/ogre/particles.cpp | 217 +++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 13 ++ libs/openengine/ogre/renderer.cpp | 12 ++ libs/openengine/ogre/renderer.hpp | 2 + 5 files changed, 248 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 4e6d3b3c45..d546ca2712 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -351,7 +351,7 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { - Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); + Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, @@ -359,6 +359,9 @@ class NIFObjectLoader emitter->setEmissionRate(partctrl->emitRate); emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, partctrl->lifetime+partctrl->lifetimeRandom); + emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); + emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); + emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); Nif::ExtraPtr e = partctrl->extra; while(!e.empty()) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 61ebddc562..a6bc78d5fb 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -2,9 +2,226 @@ #include #include +#include #include #include +/* FIXME: "Nif" isn't really an appropriate emitter name. */ +class NifEmitter : public Ogre::ParticleEmitter +{ +public: + /** Command object for the emitter width (see Ogre::ParamCommand).*/ + class CmdWidth : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getWidth()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setWidth(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for the emitter height (see Ogre::ParamCommand).*/ + class CmdHeight : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getHeight()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setHeight(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for the emitter depth (see Ogre::ParamCommand).*/ + class CmdDepth : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getDepth()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setDepth(Ogre::StringConverter::parseReal(val)); + } + }; + + + NifEmitter(Ogre::ParticleSystem *psys) + : Ogre::ParticleEmitter(psys) + { + initDefaults("Nif"); + } + + /** See Ogre::ParticleEmitter. */ + unsigned short _getEmissionCount(Ogre::Real timeElapsed) + { + // Use basic constant emission + return genConstantEmissionCount(timeElapsed); + } + + /** See Ogre::ParticleEmitter. */ + void _initParticle(Ogre::Particle *particle) + { + Ogre::Vector3 xOff, yOff, zOff; + + // Call superclass + ParticleEmitter::_initParticle(particle); + + xOff = Ogre::Math::SymmetricRandom() * mXRange; + yOff = Ogre::Math::SymmetricRandom() * mYRange; + zOff = Ogre::Math::SymmetricRandom() * mZRange; + + particle->position = mPosition + xOff + yOff + zOff; + + // Generate complex data by reference + genEmissionColour(particle->colour); + genEmissionDirection(particle->direction); + genEmissionVelocity(particle->direction); + + // Generate simpler data + particle->timeToLive = particle->totalTimeToLive = genEmissionTTL(); + } + + /** Overloaded to update the trans. matrix */ + void setDirection(const Ogre::Vector3 &dir) + { + ParticleEmitter::setDirection(dir); + genAreaAxes(); + } + + /** Sets the size of the area from which particles are emitted. + @param + size Vector describing the size of the area. The area extends + around the center point by half the x, y and z components of + this vector. The box is aligned such that it's local Z axis points + along it's direction (see setDirection) + */ + void setSize(const Ogre::Vector3 &size) + { + mSize = size; + genAreaAxes(); + } + + /** Sets the size of the area from which particles are emitted. + @param x,y,z + Individual axis lengths describing the size of the area. The area + extends around the center point by half the x, y and z components + of this vector. The box is aligned such that it's local Z axis + points along it's direction (see setDirection) + */ + void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z) + { + mSize.x = x; + mSize.y = y; + mSize.z = z; + genAreaAxes(); + } + + /** Sets the width (local x size) of the emitter. */ + void setWidth(Ogre::Real width) + { + mSize.x = width; + genAreaAxes(); + } + /** Gets the width (local x size) of the emitter. */ + Ogre::Real getWidth(void) const + { return mSize.x; } + /** Sets the height (local y size) of the emitter. */ + void setHeight(Ogre::Real height) + { + mSize.y = height; + genAreaAxes(); + } + /** Gets the height (local y size) of the emitter. */ + Ogre::Real getHeight(void) const + { return mSize.y; } + /** Sets the depth (local y size) of the emitter. */ + void setDepth(Ogre::Real depth) + { + mSize.z = depth; + genAreaAxes(); + } + /** Gets the depth (local y size) of the emitter. */ + Ogre::Real getDepth(void) const + { return mSize.z; } + +protected: + /// Size of the area + Ogre::Vector3 mSize; + + /// Local axes, not normalised, their magnitude reflects area size + Ogre::Vector3 mXRange, mYRange, mZRange; + + /// Internal method for generating the area axes + void genAreaAxes(void) + { + Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); + + mXRange = mLeft * (mSize.x * 0.5f); + mYRange = mUp * (mSize.y * 0.5f); + mZRange = mDirection * (mSize.z * 0.5f); + } + + /** Internal for initializing some defaults and parameters + @return True if custom parameters need initialising + */ + bool initDefaults(const Ogre::String &t) + { + // Defaults + mDirection = Ogre::Vector3::UNIT_Z; + mUp = Ogre::Vector3::UNIT_Y; + setSize(100.0f, 100.0f, 100.0f); + mType = t; + + // Set up parameters + if(createParamDictionary(mType + "Emitter")) + { + addBaseParameters(); + Ogre::ParamDictionary *dict = getParamDictionary(); + + // Custom params + dict->addParameter(Ogre::ParameterDef("width", + "Width of the shape in world coordinates.", + Ogre::PT_REAL), + &msWidthCmd); + dict->addParameter(Ogre::ParameterDef("height", + "Height of the shape in world coordinates.", + Ogre::PT_REAL), + &msHeightCmd); + dict->addParameter(Ogre::ParameterDef("depth", + "Depth of the shape in world coordinates.", + Ogre::PT_REAL), + &msDepthCmd); + + return true; + } + return false; + } + + /// Command objects + static CmdWidth msWidthCmd; + static CmdHeight msHeightCmd; + static CmdDepth msDepthCmd; +}; +NifEmitter::CmdWidth NifEmitter::msWidthCmd; +NifEmitter::CmdHeight NifEmitter::msHeightCmd; +NifEmitter::CmdDepth NifEmitter::msDepthCmd; + +Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleEmitter *emit = OGRE_NEW NifEmitter(psys); + mEmitters.push_back(emit); + return emit; +} + + class GrowFadeAffector : public Ogre::ParticleAffector { public: diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp index 0d88a348e3..e1f3fd282c 100644 --- a/libs/openengine/ogre/particles.hpp +++ b/libs/openengine/ogre/particles.hpp @@ -1,8 +1,21 @@ #ifndef OENGINE_OGRE_PARTICLES_H #define OENGINE_OGRE_PARTICLES_H +#include #include +/** Factory class for NifEmitter. */ +class NifEmitterFactory : public Ogre::ParticleEmitterFactory +{ +public: + /** See ParticleEmitterFactory */ + Ogre::String getName() const + { return "Nif"; } + + /** See ParticleEmitterFactory */ + Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys); +}; + /** Factory class for GrowFadeAffector. */ class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory { diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index fcc4961b50..7be7137969 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -110,6 +110,11 @@ void OgreRenderer::loadPlugins() void OgreRenderer::unloadPlugins() { + std::vector::iterator ei; + for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();ei++) + OGRE_DELETE (*ei); + mEmitterFactories.clear(); + std::vector::iterator ai; for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();ai++) OGRE_DELETE (*ai); @@ -206,6 +211,13 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); + + Ogre::ParticleEmitterFactory *emitter; + emitter = OGRE_NEW NifEmitterFactory(); + Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter); + mEmitterFactories.push_back(emitter); + + Ogre::ParticleAffectorFactory *affector; affector = OGRE_NEW GrowFadeAffectorFactory(); Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index ea46f5ae62..962ae4f2ec 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -40,6 +40,7 @@ namespace Ogre class SceneManager; class Camera; class Viewport; + class ParticleEmitterFactory; class ParticleAffectorFactory; } @@ -95,6 +96,7 @@ namespace OEngine Ogre::D3D9Plugin* mD3D9Plugin; #endif Fader* mFader; + std::vector mEmitterFactories; std::vector mAffectorFactories; bool logging; From dd981077b955e8be6123c05765467112b61d5cdc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:16:57 -0700 Subject: [PATCH 1063/1483] Handle the vertical and horizontal parameters of Nif particles Note that 'horizontal' is mapped to rotate around the Z axis, not Y. The Nif particle parameters seem to be set up to expect a normal OpenGL (Direct3D?) orientation, rather than the 90-degree pitch offset of the game. --- components/nifogre/ogrenifloader.cpp | 10 ++- libs/openengine/ogre/particles.cpp | 125 ++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d546ca2712..78b60d7121 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -352,16 +352,18 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); - emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, partctrl->velocity+partctrl->velocityRandom); emitter->setEmissionRate(partctrl->emitRate); emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, partctrl->lifetime+partctrl->lifetimeRandom); emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); - emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); - emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); + emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); + emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); + emitter->setParameter("vertical_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalDir).valueDegrees())); + emitter->setParameter("vertical_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalAngle).valueDegrees())); + emitter->setParameter("horizontal_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalDir).valueDegrees())); + emitter->setParameter("horizontal_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalAngle).valueDegrees())); Nif::ExtraPtr e = partctrl->extra; while(!e.empty()) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index a6bc78d5fb..5cb92bf0f3 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -52,6 +52,70 @@ public: } }; + /** Command object for the emitter vertical_direction (see Ogre::ParamCommand).*/ + class CmdVerticalDir : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getVerticalDirection().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setVerticalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter vertical_angle (see Ogre::ParamCommand).*/ + class CmdVerticalAngle : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getVerticalAngle().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setVerticalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter horizontal_direction (see Ogre::ParamCommand).*/ + class CmdHorizontalDir : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getHorizontalDirection().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setHorizontalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter horizontal_angle (see Ogre::ParamCommand).*/ + class CmdHorizontalAngle : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getHorizontalAngle().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setHorizontalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + NifEmitter(Ogre::ParticleSystem *psys) : Ogre::ParticleEmitter(psys) @@ -82,7 +146,14 @@ public: // Generate complex data by reference genEmissionColour(particle->colour); - genEmissionDirection(particle->direction); + + // NOTE: We do not use mDirection/mAngle for the initial direction. + Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); + Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); + particle->direction = (Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X) * + Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z)) * + Ogre::Vector3::UNIT_Z; + genEmissionVelocity(particle->direction); // Generate simpler data @@ -152,10 +223,36 @@ public: Ogre::Real getDepth(void) const { return mSize.z; } + void setVerticalDirection(Ogre::Radian vdir) + { mVerticalDir = vdir; } + Ogre::Radian getVerticalDirection(void) const + { return mVerticalDir; } + + void setVerticalAngle(Ogre::Radian vangle) + { mVerticalAngle = vangle; } + Ogre::Radian getVerticalAngle(void) const + { return mVerticalAngle; } + + void setHorizontalDirection(Ogre::Radian hdir) + { mHorizontalDir = hdir; } + Ogre::Radian getHorizontalDirection(void) const + { return mHorizontalDir; } + + void setHorizontalAngle(Ogre::Radian hangle) + { mHorizontalAngle = hangle; } + Ogre::Radian getHorizontalAngle(void) const + { return mHorizontalAngle; } + + protected: /// Size of the area Ogre::Vector3 mSize; + Ogre::Radian mVerticalDir; + Ogre::Radian mVerticalAngle; + Ogre::Radian mHorizontalDir; + Ogre::Radian mHorizontalAngle; + /// Local axes, not normalised, their magnitude reflects area size Ogre::Vector3 mXRange, mYRange, mZRange; @@ -163,7 +260,6 @@ protected: void genAreaAxes(void) { Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); - mXRange = mLeft * (mSize.x * 0.5f); mYRange = mUp * (mSize.y * 0.5f); mZRange = mDirection * (mSize.z * 0.5f); @@ -200,6 +296,23 @@ protected: Ogre::PT_REAL), &msDepthCmd); + dict->addParameter(Ogre::ParameterDef("vertical_direction", + "Vertical direction of emitted particles (in degrees).", + Ogre::PT_REAL), + &msVerticalDirCmd); + dict->addParameter(Ogre::ParameterDef("vertical_angle", + "Vertical direction variance of emitted particles (in degrees).", + Ogre::PT_REAL), + &msVerticalAngleCmd); + dict->addParameter(Ogre::ParameterDef("horizontal_direction", + "Horizontal direction of emitted particles (in degrees).", + Ogre::PT_REAL), + &msHorizontalDirCmd); + dict->addParameter(Ogre::ParameterDef("horizontal_angle", + "Horizontal direction variance of emitted particles (in degrees).", + Ogre::PT_REAL), + &msHorizontalAngleCmd); + return true; } return false; @@ -209,10 +322,18 @@ protected: static CmdWidth msWidthCmd; static CmdHeight msHeightCmd; static CmdDepth msDepthCmd; + static CmdVerticalDir msVerticalDirCmd; + static CmdVerticalAngle msVerticalAngleCmd; + static CmdHorizontalDir msHorizontalDirCmd; + static CmdHorizontalAngle msHorizontalAngleCmd; }; NifEmitter::CmdWidth NifEmitter::msWidthCmd; NifEmitter::CmdHeight NifEmitter::msHeightCmd; NifEmitter::CmdDepth NifEmitter::msDepthCmd; +NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd; +NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd; +NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd; +NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd; Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) { From 80a4345787d71d60e7d202bd1898ce2b5e4694ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:26:34 -0700 Subject: [PATCH 1064/1483] Keep particles in local space --- components/nifogre/ogrenifloader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 78b60d7121..40730a586f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -436,6 +436,9 @@ class NIFObjectLoader particledata->particleRadius*2.0f); partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); + // TODO: There is probably a field or flag to specify this, as some + // particle effects have it and some don't. + partsys->setKeepParticlesInLocalSpace(true); Nif::ControllerPtr ctrl = partnode->controller; while(!ctrl.empty()) From 0b363ba36e41e28bf3193e5774533218e68e6fa6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:42:32 -0700 Subject: [PATCH 1065/1483] Handle NiParticleColorModifier with Ogre's ColourInterpolator Note that Ogre's ColourInterpolator has a maximum of six color stages. This seems to be fine so far, but if we want anything better, we'll need a custom affector for it. --- components/nifogre/ogrenifloader.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 40730a586f..a26f431311 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -386,14 +386,30 @@ class NIFObjectLoader affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection)); affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition)); } + else if(e->recType == Nif::RC_NiParticleColorModifier) + { + const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiColorData *clrdata = cl->data.getPtr(); + + Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator"); + size_t num_colors = std::min(6, clrdata->mKeyList.mKeys.size()); + for(size_t i = 0;i < num_colors;i++) + { + Ogre::ColourValue color; + color.r = clrdata->mKeyList.mKeys[i].mValue[0]; + color.g = clrdata->mKeyList.mKeys[i].mValue[1]; + color.b = clrdata->mKeyList.mKeys[i].mValue[2]; + color.a = clrdata->mKeyList.mKeys[i].mValue[3]; + affector->setParameter("colour"+Ogre::StringConverter::toString(i), + Ogre::StringConverter::toString(color)); + affector->setParameter("time"+Ogre::StringConverter::toString(i), + Ogre::StringConverter::toString(clrdata->mKeyList.mKeys[i].mTime)); + } + } else if(e->recType == Nif::RC_NiParticleRotation) { // TODO: Implement (Ogre::RotationAffector?) } - else if(e->recType == Nif::RC_NiParticleColorModifier) - { - // TODO: Implement (Ogre::ColourInterpolatorAffector?) - } else warn("Unhandled particle modifier "+e->recName); e = e->extra; From 254c6840d817abd9b8b2c7428a8c1f359316ec0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 18:22:30 -0700 Subject: [PATCH 1066/1483] Fix particle direction --- libs/openengine/ogre/particles.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 5cb92bf0f3..707bd75e08 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -148,10 +148,10 @@ public: genEmissionColour(particle->colour); // NOTE: We do not use mDirection/mAngle for the initial direction. - Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); - particle->direction = (Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X) * - Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z)) * + Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); + particle->direction = (Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) * + Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) * Ogre::Vector3::UNIT_Z; genEmissionVelocity(particle->direction); From acb1b5f0025a01e827a18159aeef9a95cbbebdf4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 22:54:32 -0700 Subject: [PATCH 1067/1483] Try to handle NiBSAnimationNode This is still incomplete guess work. Currently it seems as though flag 0x20 specifies whether the controllers auto-play (if on), rather than follow the object's animation time. --- components/nifogre/ogrenifloader.cpp | 26 ++++++++++++++++---------- components/nifogre/skeleton.cpp | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a26f431311..ec53b79aa5 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -492,7 +492,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags) + ObjectList &objectlist, int flags, int animflags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -503,7 +503,10 @@ class NIFObjectLoader if (node->name.find("marker") != std::string::npos) return; - flags |= node->flags; + if(node->recType == Nif::RC_NiBSAnimationNode) + animflags |= node->flags; + else + flags |= node->flags; Nif::ExtraPtr e = node->extra; while(!e.empty()) @@ -539,9 +542,10 @@ class NIFObjectLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, false)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -552,9 +556,10 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -599,9 +604,10 @@ class NIFObjectLoader const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, true)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -627,7 +633,7 @@ class NIFObjectLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags); } } } @@ -674,7 +680,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist, flags); + createObjects(name, group, sceneMgr, node, objectlist, flags, 0); } }; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index e97e91ef03..28df4894db 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -164,6 +164,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles From f4695ec4ac487812b2b9120e1ebd90726ba9fd58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 00:06:40 -0700 Subject: [PATCH 1068/1483] Cleanup NIFObjectLoader some --- components/nifogre/ogrenifloader.cpp | 213 +++++++++++++-------------- 1 file changed, 106 insertions(+), 107 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index ec53b79aa5..631d397283 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -331,9 +331,9 @@ public: -/** Manual resource loader for NIF objects (meshes, particle systems, etc). - * This is the main class responsible for translating the internal NIF - * structures into something Ogre can use. +/** Object creator for NIFs. This is the main class responsible for creating + * "live" Ogre objects (entities, particle systems, controllers, etc) from + * their NIF equivalents. */ class NIFObjectLoader { @@ -349,6 +349,57 @@ class NIFObjectLoader } + static void createEntity(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, ObjectList &objectlist, + const Nif::Node *node, int flags, int animflags) + { + const Nif::NiTriShape *shape = static_cast(node); + + std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); + if(shape->name.length() > 0) + fullname += "@shape="+shape->name; + Misc::StringUtils::toLower(fullname); + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + if(meshMgr.getByName(fullname).isNull()) + NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); + + Ogre::Entity *entity = sceneMgr->createEntity(fullname); + entity->setVisible(!(flags&0x01)); + + objectlist.mEntities.push_back(entity); + if(objectlist.mSkelBase) + { + if(entity->hasSkeleton()) + entity->shareSkeletonInstanceWith(objectlist.mSkelBase); + else + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + } + } + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); + + const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } + } + + static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); @@ -416,9 +467,9 @@ class NIFObjectLoader } } - static Ogre::ParticleSystem *createParticleSystem(const std::string &name, const std::string &group, - Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, - const Nif::Node *partnode) + static void createParticleSystem(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, ObjectList &objectlist, + const Nif::Node *partnode, int flags, int animflags) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -426,67 +477,63 @@ class NIFObjectLoader else if(partnode->recType == Nif::RC_NiRotatingParticles) particledata = static_cast(partnode)->data.getPtr(); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); - try { - std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - bool needTangents = false; + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; + bool needTangents = false; - partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, needTangents)); + partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + wireprop, needTangents)); - partsys->setDefaultDimensions(particledata->particleRadius*2.0f, - particledata->particleRadius*2.0f); - partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->numParticles); - // TODO: There is probably a field or flag to specify this, as some - // particle effects have it and some don't. - partsys->setKeepParticlesInLocalSpace(true); + partsys->setDefaultDimensions(particledata->particleRadius*2.0f, + particledata->particleRadius*2.0f); + partsys->setCullIndividually(false); + partsys->setParticleQuota(particledata->numParticles); + // TODO: There is probably a field or flag to specify this, as some + // particle effects have it and some don't. + partsys->setKeepParticlesInLocalSpace(true); - Nif::ControllerPtr ctrl = partnode->controller; - while(!ctrl.empty()) + Nif::ControllerPtr ctrl = partnode->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiParticleSystemController) { - if(ctrl->recType == Nif::RC_NiParticleSystemController) + const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); + + createParticleEmitterAffectors(partsys, partctrl); + if(!partctrl->emitter.empty() && !partsys->isAttached()) { - const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); - - createParticleEmitterAffectors(partsys, partctrl); - if(!partctrl->emitter.empty() && !partsys->isAttached()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); - Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); - entitybase->attachObjectToBone(trgtbone->getName(), partsys); - } + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - ctrl = ctrl->next; - } - - if(!partsys->isAttached()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); - Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); - entitybase->attachObjectToBone(trgtbone->getName(), partsys); } + ctrl = ctrl->next; } - catch(std::exception &e) { - std::cerr<< "Particles exception: "<destroyParticleSystem(partsys); - partsys = NULL; - }; - return partsys; + + if(!partsys->isAttached()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); + } + + partsys->setVisible(!(flags&0x01)); + objectlist.mParticles.push_back(partsys); } @@ -569,61 +616,13 @@ class NIFObjectLoader if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { - const Nif::NiTriShape *shape = static_cast(node); - - std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(shape->name.length() > 0) - fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - if(meshMgr.getByName(fullname).isNull()) - NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - - Ogre::Entity *entity = sceneMgr->createEntity(fullname); - entity->setVisible(!(flags&0x01)); - - objectlist.mEntities.push_back(entity); - if(objectlist.mSkelBase) - { - if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(objectlist.mSkelBase); - else - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); - } - } - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiUVController) - { - const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); - - const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - ctrl = ctrl->next; - } + createEntity(name, group, sceneMgr, objectlist, node, flags, animflags); } if((node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { - Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); - if(partsys != NULL) - { - partsys->setVisible(!(flags&0x01)); - objectlist.mParticles.push_back(partsys); - } + createParticleSystem(name, group, sceneMgr, objectlist, node, flags, animflags); } const Nif::NiNode *ninode = dynamic_cast(node); From 0c33dd86d595346561b37d8d90b69f5865fc9460 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 14 Apr 2013 17:04:55 +0200 Subject: [PATCH 1069/1483] added basic cell table --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/cell.cpp | 20 ++++++++++++++++++++ apps/opencs/model/world/cell.hpp | 17 +++++++++++++++++ apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/idcollection.hpp | 6 ++++-- apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadcell.cpp | 18 ++++++++++++++++++ components/esm/loadcell.hpp | 3 +++ 13 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/world/cell.cpp create mode 100644 apps/opencs/model/world/cell.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5c15938bda..efc3551fd3 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -22,7 +22,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid data record idcollection commands columnbase scriptcontext + universalid data record idcollection commands columnbase scriptcontext cell ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp new file mode 100644 index 0000000000..759468fa8f --- /dev/null +++ b/apps/opencs/model/world/cell.cpp @@ -0,0 +1,20 @@ + +#include "cell.hpp" + +#include + +void CSMWorld::Cell::load (ESM::ESMReader &esm) +{ + mName = mId; + + ESM::Cell::load (esm, true); /// \todo set this to false, once the bug in ESM::Cell::load is fixed + + if (!(mData.mFlags & Interior)) + { + std::ostringstream stream; + + stream << "#" << mData.mX << " " << mData.mY; + + mId = stream.str(); + } +} \ No newline at end of file diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp new file mode 100644 index 0000000000..6a9676a559 --- /dev/null +++ b/apps/opencs/model/world/cell.hpp @@ -0,0 +1,17 @@ +#ifndef CSM_WOLRD_CELL_H +#define CSM_WOLRD_CELL_H + +#include + +namespace CSMWorld +{ + /// \brief Wrapper for Cell record + struct Cell : public ESM::Cell + { + std::string mId; + + void load (ESM::ESMReader &esm); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 9f6b186c0c..83702b05c6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -119,6 +119,11 @@ CSMWorld::Data::Data() mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); + mCells.addColumn (new StringIdColumn); + mCells.addColumn (new RecordStateColumn); + mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); + mCells.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -130,6 +135,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); + addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell); } CSMWorld::Data::~Data() @@ -248,6 +254,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSpells() return mSpells; } +const CSMWorld::IdCollection& CSMWorld::Data::getCells() const +{ + return mCells; +} + +CSMWorld::IdCollection& CSMWorld::Data::getCells() +{ + return mCells; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -293,6 +309,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_REGN: mRegions.load (reader, base); break; case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; case ESM::REC_SPEL: mSpells.load (reader, base); break; + case ESM::REC_CELL: mCells.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index d7b69ba5e3..03a2448f11 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -20,6 +20,7 @@ #include "idcollection.hpp" #include "universalid.hpp" +#include "cell.hpp" class QAbstractItemModel; @@ -38,6 +39,7 @@ namespace CSMWorld IdCollection mRegions; IdCollection mBirthsigns; IdCollection mSpells; + IdCollection mCells; std::vector mModels; std::map mModelIndex; @@ -98,6 +100,10 @@ namespace CSMWorld IdCollection& getSpells(); + const IdCollection& getCells() const; + + IdCollection& getCells(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 3bf53349e6..4afe9cbaab 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -325,10 +325,10 @@ namespace CSMWorld { std::string id = reader.getHNOString ("NAME"); - int index = searchId (id); - if (reader.isNextSub ("DELE")) { + int index = searchId (id); + reader.skipRecord(); if (index==-1) @@ -354,6 +354,8 @@ namespace CSMWorld record.mId = id; record.load (reader); + int index = searchId (record.mId); + if (index==-1) { // new record diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 11f4877886..c0241bc383 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -28,6 +28,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -45,6 +46,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 5586b22e79..9b52aded1f 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -55,7 +55,9 @@ namespace CSMWorld Type_Birthsigns, Type_Birthsign, Type_Spells, - Type_Spell + Type_Spell, + Type_Cells, + Type_Cell }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index dfdcb10365..a684b85c5b 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -125,6 +125,10 @@ void CSVDoc::View::setupWorldMenu() QAction *spells = new QAction (tr ("Spells"), this); connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); world->addAction (spells); + + QAction *cells = new QAction (tr ("Cells"), this); + connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView())); + world->addAction (cells); } void CSVDoc::View::setupUi() @@ -325,6 +329,11 @@ void CSVDoc::View::addSpellsSubView() addSubView (CSMWorld::UniversalId::Type_Spells); } +void CSVDoc::View::addCellsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Cells); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 9241efbb9a..a240d3b01d 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -133,6 +133,8 @@ namespace CSVDoc void addBirthsignsSubView(); void addSpellsSubView(); + + void addCellsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 8f7887f3b9..0ce3d3d6db 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -26,6 +26,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_Spells, + CSMWorld::UniversalId::Type_Cells, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 5cbf1de2b7..77e4d3691c 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -356,4 +356,22 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) return true; } + void Cell::blank() + { + mName.clear(); + mRegion.clear(); + mWater = 0; + mWaterInt = false; + mMapColor = 0; + mNAM0 = 0; + + mData.mFlags = 0; + mData.mX = 0; + mData.mY = 0; + + mAmbi.mAmbient = 0; + mAmbi.mSunlight = 0; + mAmbi.mFog = 0; + mAmbi.mFogDensity = 0; + } } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 44412b5eb9..d7f64817f8 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -140,6 +140,9 @@ struct Cell * Since they are comparably rare, we use a separate method for this. */ static bool getNextMVRF(ESMReader &esm, MovedCellRef &mref); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 71148121a2d5327156d16fb0ceb779117cc90a96 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 14 Apr 2013 17:10:37 +0200 Subject: [PATCH 1070/1483] added flag columns to cell table --- apps/opencs/model/world/data.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 83702b05c6..604b55109d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -123,6 +123,9 @@ CSMWorld::Data::Data() mCells.addColumn (new RecordStateColumn); mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn); + mCells.addColumn (new FlagColumn ("Sleep forbidden", ESM::Cell::NoSleep)); + mCells.addColumn (new FlagColumn ("Interior Water", ESM::Cell::HasWater)); + mCells.addColumn (new FlagColumn ("Interior Sky", ESM::Cell::QuasiEx)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 48f46e505cb9a1a1e7adde097ba1c69132eee54b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Apr 2013 17:37:39 +0200 Subject: [PATCH 1071/1483] Look in exterior cells first (chargen_crate_01_empty is in the prison ship but also outside of it, the one outside needs to be disabled) --- apps/openmw/mwworld/cells.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 4838cfefa5..87ac1c6d7f 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -165,6 +165,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce else return Ptr(); } + MWWorld::Ptr ptr; if (MWWorld::LiveCellRef *ref = cell.mActivators.find (name)) @@ -246,16 +247,16 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) } // Then check cells that are already listed - for (std::map::iterator iter = mInteriors.begin(); - iter!=mInteriors.end(); ++iter) + for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); + iter!=mExteriors.end(); ++iter) { Ptr ptr = getPtrAndCache (name, iter->second); if (!ptr.isEmpty()) - return ptr; + return ptr; } - for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); - iter!=mExteriors.end(); ++iter) + for (std::map::iterator iter = mInteriors.begin(); + iter!=mInteriors.end(); ++iter) { Ptr ptr = getPtrAndCache (name, iter->second); if (!ptr.isEmpty()) @@ -266,7 +267,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) const MWWorld::Store &cells = mStore.get(); MWWorld::Store::iterator iter; - for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter) + for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter) { Ptr::CellStore *cellStore = getCellStore (&(*iter)); @@ -276,7 +277,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) return ptr; } - for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter) + for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter) { Ptr::CellStore *cellStore = getCellStore (&(*iter)); From a57fbbb168a68201b22b63f218397e2758d2de22 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Apr 2013 17:51:17 +0200 Subject: [PATCH 1072/1483] Fix wrong detection of diseases --- apps/openmw/mwmechanics/spells.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index e2da7cdc86..e10dcdc93d 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -80,7 +80,7 @@ namespace MWMechanics const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - if (spell->mData.mFlags & ESM::Spell::ST_Disease) + if (spell->mData.mType == ESM::Spell::ST_Disease) return true; } @@ -94,7 +94,7 @@ namespace MWMechanics const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - if (spell->mData.mFlags & ESM::Spell::ST_Blight) + if (spell->mData.mType == ESM::Spell::ST_Blight) return true; } From b2b953d2a88d844c35ef58b3b5303d12d8541b48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 14 Apr 2013 19:34:55 +0200 Subject: [PATCH 1073/1483] added region column to cell table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 9242e8a23b..f1d8d4ae62 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -748,6 +748,31 @@ namespace CSMWorld return true; } }; + + template + struct RegionColumn : public Column + { + RegionColumn() : Column ("Region", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mRegion.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mRegion = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 604b55109d..dedbfc4e7d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -126,6 +126,7 @@ CSMWorld::Data::Data() mCells.addColumn (new FlagColumn ("Sleep forbidden", ESM::Cell::NoSleep)); mCells.addColumn (new FlagColumn ("Interior Water", ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn ("Interior Sky", ESM::Cell::QuasiEx)); + mCells.addColumn (new RegionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 4e0233cf06384472ef49f47de87fcccc1068066c Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 14 Apr 2013 21:42:37 +0200 Subject: [PATCH 1074/1483] Base local rotations implementation --- .../mwscript/transformationextensions.cpp | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6c4fb0f4bd..922353974d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -553,26 +553,30 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why + Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why (probably framerate) runtime.pop(); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + float *objRot = ptr.getRefData().getPosition().rot; - //Axis in morrowind are inverted - if (axis == "y") + if (axis == "x") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + objRot[0]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_X));; } - else if (axis == "x") + else if (axis == "y") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + objRot[1]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Y)); } else if (axis == "z") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + objRot[2]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Z)); } + else throw std::runtime_error ("invalid rotation axis: " + axis); } From bf8bc989fc0184f59aa40f9d3a028d4fad6f749b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 12:52:20 -0700 Subject: [PATCH 1075/1483] Recognize and partly handle NiBSParticleNode --- components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 1 + components/nifogre/ogrenifloader.cpp | 12 +++++++----- components/nifogre/skeleton.cpp | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 3b41e96a70..2c4f3506ea 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -208,7 +208,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiNode", &construct , RC_NiNode }, { "AvoidNode", &construct , RC_NiNode }, - { "NiBSParticleNode", &construct , RC_NiNode }, + { "NiBSParticleNode", &construct , RC_NiBSParticleNode }, { "NiBSAnimationNode", &construct , RC_NiBSAnimationNode }, { "NiBillboardNode", &construct , RC_NiNode }, { "NiTriShape", &construct , RC_NiTriShape }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 361af3f64c..97b10503e8 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -39,6 +39,7 @@ enum RecordType RC_NiTriShape, RC_NiRotatingParticles, RC_NiAutoNormalParticles, + RC_NiBSParticleNode, RC_NiCamera, RC_NiTexturingProperty, RC_NiMaterialProperty, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 631d397283..1ed5e24a36 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -469,7 +469,7 @@ class NIFObjectLoader static void createParticleSystem(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, ObjectList &objectlist, - const Nif::Node *partnode, int flags, int animflags) + const Nif::Node *partnode, int flags, int partflags) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -539,7 +539,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags, int animflags) + ObjectList &objectlist, int flags, int animflags, int partflags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -552,6 +552,8 @@ class NIFObjectLoader if(node->recType == Nif::RC_NiBSAnimationNode) animflags |= node->flags; + else if(node->recType == Nif::RC_NiBSParticleNode) + partflags |= node->flags; else flags |= node->flags; @@ -622,7 +624,7 @@ class NIFObjectLoader if((node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { - createParticleSystem(name, group, sceneMgr, objectlist, node, flags, animflags); + createParticleSystem(name, group, sceneMgr, objectlist, node, flags, partflags); } const Nif::NiNode *ninode = dynamic_cast(node); @@ -632,7 +634,7 @@ class NIFObjectLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags, partflags); } } } @@ -679,7 +681,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist, flags, 0); + createObjects(name, group, sceneMgr, node, objectlist, flags, 0, 0); } }; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 28df4894db..75bc907152 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -165,6 +165,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ + node->recType == Nif::RC_NiBSParticleNode || node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles From 7000a1aa3eba373f33741e7f208e1af8bd6c45e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 13:50:55 -0700 Subject: [PATCH 1076/1483] Add a ParticleSystemController --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 1ed5e24a36..69f14b663d 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -329,6 +329,35 @@ public: typedef DefaultFunction Function; }; +class ParticleSystemController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::ParticleSystem *mParticleSys; + float mEmitStart; + float mEmitStop; + + public: + Value(Ogre::ParticleSystem *psys, const Nif::NiParticleSystemController *pctrl) + : mParticleSys(psys) + , mEmitStart(pctrl->startTime) + , mEmitStop(pctrl->stopTime) + { + } + + Ogre::Real getValue() const + { return 0.0f; } + + void setValue(Ogre::Real value) + { + mParticleSys->setEmitting(value >= mEmitStart && value < mEmitStop); + } + }; + + typedef DefaultFunction Function; +}; /** Object creator for NIFs. This is the main class responsible for creating @@ -521,6 +550,13 @@ class NIFObjectLoader Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } + + Ogre::ControllerValueRealPtr srcval((partflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&0x20))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } From f9dee25fd1c0218fd40ac11e2b3406bbb70283b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 16:56:35 -0700 Subject: [PATCH 1077/1483] Store the base skeleton entity in MWRender::Animation --- apps/openmw/mwrender/animation.cpp | 21 ++++++++++++--------- apps/openmw/mwrender/animation.hpp | 3 ++- apps/openmw/mwrender/npcanimation.cpp | 5 ++--- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a849b20efe..d6f762ab76 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -33,6 +33,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mController(NULL) , mInsert(NULL) + , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) @@ -65,7 +66,7 @@ Animation::~Animation() void Animation::setAnimationSources(const std::vector &names) { - if(!mObjectList.mSkelBase) + if(!mSkelBase) return; Ogre::SceneManager *sceneMgr = mInsert->getCreator(); @@ -81,7 +82,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.clear(); Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { @@ -127,7 +128,7 @@ void Animation::setAnimationSources(const std::vector &names) if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); } for(int i = 0;i < skel->getNumAnimations();i++) @@ -152,7 +153,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model mObjectList = NifOgre::Loader::createObjects(mInsert, model); if(mObjectList.mSkelBase) { - Ogre::AnimationStateSet *aset = mObjectList.mSkelBase->getAllAnimationStates(); + mSkelBase = mObjectList.mSkelBase; + + Ogre::AnimationStateSet *aset = mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -164,7 +167,7 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); @@ -182,9 +185,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model Ogre::Node *Animation::getNode(const std::string &name) { - if(mObjectList.mSkelBase) + if(mSkelBase) { - Ogre::SkeletonInstance *skel = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); if(skel->hasBone(name)) return skel->getBone(name); } @@ -508,11 +511,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) for(size_t i = 0;i < mCurrentControllers->size();i++) (*mCurrentControllers)[i].update(); - if(mObjectList.mSkelBase) + if(mSkelBase) { // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. - mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + mSkelBase->getAllAnimationStates()->_notifyDirty(); } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 029c56523d..32344a2c02 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -42,7 +42,8 @@ protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; - Ogre::SceneNode* mInsert; + Ogre::SceneNode *mInsert; + Ogre::Entity *mSkelBase; NifOgre::ObjectList mObjectList; std::map mTextKeys; Ogre::Node *mAccumRoot; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 96220f47d0..a2446b8671 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -359,8 +359,7 @@ void NpcAnimation::updateParts(bool forceupdate) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { - NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, - mInsert, model); + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); for(size_t i = 0;i < objects.mEntities.size();i++) { objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); @@ -408,7 +407,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mObjectList.mSkelBase->getSkeleton(); + const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; From 2693b785362ec30ba729c7807ad20d7a0d2d74f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Apr 2013 02:56:23 +0200 Subject: [PATCH 1078/1483] Add initial player inventory when new game is started --- apps/openmw/engine.cpp | 1 + apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/armor.cpp | 19 +++++++----------- apps/openmw/mwclass/armor.hpp | 5 +++-- apps/openmw/mwclass/clothing.cpp | 20 ++++--------------- apps/openmw/mwclass/clothing.hpp | 3 ++- apps/openmw/mwclass/weapon.cpp | 8 ++++---- apps/openmw/mwclass/weapon.hpp | 3 ++- .../mwmechanics/mechanicsmanagerimp.cpp | 12 +++++++++++ apps/openmw/mwworld/actionequip.cpp | 10 +++++++--- apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 3 ++- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++++++--- apps/openmw/mwworld/worldimp.hpp | 1 + 15 files changed, 62 insertions(+), 46 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 69e3cdc534..4472b205f7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -368,6 +368,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, mActivationDistanceOverride)); + MWBase::Environment::get().getWorld()->setupPlayer(mNewGame); //Load translation data mTranslationDataStorage.setEncoder(mEncoder); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39e985890a..bee744386f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -321,6 +321,7 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual bool vanityRotateCamera(float * rot) = 0; + virtual void setupPlayer(bool newGame) = 0; virtual void renderPlayer() = 0; virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 6791138d35..8a8f72c888 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,7 +292,7 @@ namespace MWClass ref->mBase = record; } - int Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); @@ -317,10 +317,7 @@ namespace MWClass { if((*itr).mPart == ESM::PRT_Head) { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - return 0; + return std::make_pair(0, "#{sNotifyMessage13}"); } } } @@ -331,9 +328,7 @@ namespace MWClass { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - return 0; + return std::make_pair(0, "#{sNotifyMessage14}"); } } } @@ -344,7 +339,7 @@ namespace MWClass MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(weapon == invStore.end()) - return 1; + return std::make_pair(1,""); if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || @@ -354,12 +349,12 @@ namespace MWClass weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - return 3; + return std::make_pair(3,""); } - return 1; + return std::make_pair(1,""); } } - return 1; + return std::make_pair(1,""); } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 703d3af1ed..9b8e9dd149 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,8 +67,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; - ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 6c231e0c60..3072f852d5 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,7 +238,7 @@ namespace MWClass ref->mBase = record; } - int Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); @@ -260,12 +260,7 @@ namespace MWClass for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_Head) - { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - return 0; - } + return std::make_pair(0, "#{sNotifyMessage13}"); } } @@ -274,19 +269,12 @@ namespace MWClass for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) - { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); - } - - return 0; - } + return std::make_pair(0, "#{sNotifyMessage15}"); } } } } - return 1; + return std::make_pair (1, ""); } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 1be42adbd4..a6de0cb4f0 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,8 +61,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index fbac6d89e8..6c6b3daa61 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,7 +384,7 @@ namespace MWClass ref->mBase = record; } - int Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); @@ -402,12 +402,12 @@ namespace MWClass ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - return 2; + return std::make_pair (2, ""); } - return 1; + return std::make_pair (1, ""); } } - return 0; + return std::make_pair (0, ""); } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 314f6bc212..05b1aee22b 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,8 +67,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4a2a2ecc69..d34c4b97f5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -155,6 +155,18 @@ namespace MWMechanics stat.setCurrent (stat.getModified()); creatureStats.setDynamic (i, stat); } + + // unequip any items that may not be equipped. we need this for when the race is changed to a beast race + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + for (int i=0; i result = MWWorld::Class::get (object).canBeEquipped (object, actor); + + // display error message if the player tried to equip something + if (!result.second.empty() && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) + MWBase::Environment::get().getWindowManager()->messageBox(result.second); + + switch(result.first) { case 0: return; @@ -48,8 +54,6 @@ namespace MWWorld assert(it != invStore.end()); - std::string npcRace = actor.get()->mBase->mRace; - bool equipped = false; // equip the item in the first free slot diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4321fc46b7..451f0c5c10 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -264,9 +264,9 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - int Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - return 1; + return std::make_pair (1, ""); } void Class::adjustPosition(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 32941c633d..b901950e31 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -245,8 +245,9 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 5495d6a021..ac5586266d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -186,7 +186,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - switch(MWWorld::Class::get (test).canBeEquipped (test, npc)) + switch(MWWorld::Class::get (test).canBeEquipped (test, npc).first) { case 0: continue; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e70aedd552..424f6f5089 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -24,6 +24,7 @@ #include "manualref.hpp" #include "cellfunctors.hpp" #include "containerstore.hpp" +#include "inventorystore.hpp" using namespace Ogre; @@ -210,9 +211,6 @@ namespace MWWorld mStore.setUp(); - mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); - mRendering->attachCameraTo(mPlayer->getPlayer()); - // global variables mGlobalVariables = new Globals (mStore); @@ -1369,6 +1367,18 @@ namespace MWWorld return mRendering->vanityRotateCamera(rot); } + void World::setupPlayer(bool newGame) + { + const ESM::NPC* player = mStore.get().find ("player"); + mPlayer = new MWWorld::Player (player, *this); + mRendering->attachCameraTo(mPlayer->getPlayer()); + if (newGame) + { + MWWorld::Class::get(mPlayer->getPlayer()).getContainerStore(mPlayer->getPlayer()).fill(player->mInventory, "", mStore); + MWWorld::Class::get(mPlayer->getPlayer()).getInventoryStore(mPlayer->getPlayer()).autoEquip (mPlayer->getPlayer()); + } + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7b12babee9..99e7cc79d9 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -363,6 +363,7 @@ namespace MWWorld virtual bool vanityRotateCamera(float * rot); + virtual void setupPlayer(bool newGame); virtual void renderPlayer(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); From 69084139aaf2c4711061dd62a84666d6f34c6d10 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 17:58:21 -0700 Subject: [PATCH 1079/1483] Use an array of objectlists, instead of one base objectlist and an array of 'animation sources' --- apps/openmw/mwrender/activatoranimation.cpp | 10 +- apps/openmw/mwrender/animation.cpp | 136 +++++++------------- apps/openmw/mwrender/animation.hpp | 14 +- apps/openmw/mwrender/creatureanimation.cpp | 21 ++- apps/openmw/mwrender/npcanimation.cpp | 27 ++-- 5 files changed, 75 insertions(+), 133 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 4630208b4b..27ddce339d 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -27,9 +27,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) std::string mesh = "meshes\\" + ref->mBase->mModel; createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *ent = mObjectList.mEntities[i]; + Ogre::Entity *ent = mObjectLists[0].mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,14 +38,12 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->setVisibilityFlags(RV_Misc); - part->setRenderQueueGroup(RQG_Alpha); } - setAnimationSource(mesh); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d6f762ab76..30bcd3c4c3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -55,68 +55,45 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - destroyObjectList(sceneMgr, mObjectList); - - for(size_t i = 0;i < mAnimationSources.size();i++) - destroyObjectList(sceneMgr, mAnimationSources[i]); - mAnimationSources.clear(); + for(size_t i = 0;i < mObjectLists.size();i++) + destroyObjectList(sceneMgr, mObjectLists[i]); + mObjectLists.clear(); } } -void Animation::setAnimationSources(const std::vector &names) +void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) { - if(!mSkelBase) - return; - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + assert(!mInsert); + mInsert = node->createChildSceneNode(); + assert(mInsert); - mCurrentControllers = &mObjectList.mControllers; - mCurrentAnim = NULL; - mCurrentKeys = NULL; - mAnimVelocity = 0.0f; - mAccumRoot = NULL; - mNonAccumRoot = NULL; - mTextKeys.clear(); - for(size_t i = 0;i < mAnimationSources.size();i++) - destroyObjectList(sceneMgr, mAnimationSources[i]); - mAnimationSources.clear(); + mObjectLists.resize(1); - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); - std::vector::const_iterator nameiter; - for(nameiter = names.begin();nameiter != names.end();nameiter++) + mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); + if(mObjectLists[0].mSkelBase) { - mAnimationSources.push_back(NifOgre::Loader::createObjectBase(sceneMgr, *nameiter)); - if(!mAnimationSources.back().mSkelBase) + mSkelBase = mObjectLists[0].mSkelBase; + + Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) { - std::cerr<< "Failed to get skeleton source "<<*nameiter < *dstval = dynamic_cast*>(objects.mControllers[i].getDestination().getPointer()); - if(!dstval) continue; - - const Ogre::String &trgtname = dstval->getNode()->getName(); - if(!skelinst->hasBone(trgtname)) continue; - - Ogre::Bone *bone = skelinst->getBone(trgtname); - dstval->setNode(bone); + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); } - for(size_t i = 0;i < objects.mControllers.size();i++) - { - if(objects.mControllers[i].getSource().isNull()) - objects.mControllers[i].setSource(ctrlval); - } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). + Ogre::SkeletonInstance *skelinst = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); - Ogre::Entity *ent = objects.mSkelBase; - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); + boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { Ogre::Bone *bone = boneiter.getNext(); @@ -143,43 +120,14 @@ void Animation::setAnimationSources(const std::vector &names) break; } } -} - -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) -{ - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectList = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectList.mSkelBase) - { - mSkelBase = mObjectList.mSkelBase; - - Ogre::AnimationStateSet *aset = mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - state->setLoop(false); - } - - // Set the bones as manually controlled since we're applying the - // transformations manually (needed if we want to apply an animation - // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); - } Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectList.mControllers.size();i++) + for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) { - if(mObjectList.mControllers[i].getSource().isNull()) - mObjectList.mControllers[i].setSource(ctrlval); + if(mObjectLists[0].mControllers[i].getSource().isNull()) + mObjectLists[0].mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectList.mControllers; + mCurrentControllers = &mObjectLists[0].mControllers; } @@ -197,9 +145,9 @@ Ogre::Node *Animation::getNode(const std::string &name) bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) + for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - if(iter->mSkelBase->hasAnimationState(anim)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(anim)) return true; } return false; @@ -449,7 +397,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) + for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { if(iter->mSkelBase->hasAnimationState(groupname)) { @@ -513,9 +461,19 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mSkelBase) { - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mSkelBase->getAllAnimationStates()->_notifyDirty(); + const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + for(size_t i = 0;i < mObjectLists.size();i++) + { + Ogre::Entity *ent = mObjectLists[i].mSkelBase; + if(!ent) continue; + + Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); + if(skelsrc != skeldst) + updateSkeletonInstance(skelsrc, skeldst); + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + ent->getAllAnimationStates()->_notifyDirty(); + } } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 32344a2c02..3c7433db98 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -44,15 +44,13 @@ protected: Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; - NifOgre::ObjectList mObjectList; + std::vector mObjectLists; std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::vector mAnimationSources; - std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -83,16 +81,6 @@ protected: bool handleEvent(float time, const std::string &evt); - /* Specifies a list of skeleton names to use as animation sources. */ - void setAnimationSources(const std::vector &names); - - /* Specifies a single skeleton name to use as an animation source. */ - void setAnimationSource(const std::string &name) - { - std::vector names(1, name); - setAnimationSources(names); - } - void createObjectList(Ogre::SceneNode *node, const std::string &model); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index c714a2372a..7084974b8c 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,10 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), model); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + std::vector names; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + names.push_back("meshes\\base_anim.nif"); + names.push_back(model); + + createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *ent = mObjectList.mEntities[i]; + Ogre::Entity *ent = mObjectLists[0].mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,19 +43,13 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->setVisibilityFlags(RV_Actors); part->setRenderQueueGroup(RQG_Alpha); } - - std::vector names; - if((ref->mBase->mFlags&ESM::Creature::Biped)) - names.push_back("meshes\\base_anim.nif"); - names.push_back(model); - setAnimationSources(names); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a2446b8671..a713ae79e1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,10 +96,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - createObjectList(node, smodel); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + std::vector skelnames(1, smodel); + if(!mNpc->isMale() && !isBeast) + skelnames.push_back("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + skelnames.push_back("meshes\\argonian_swimkna.nif"); + if(mNpc->mModel.length() > 0) + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + + createObjectList(node, smodel/*skelnames*/); + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *base = mObjectList.mEntities[i]; + Ogre::Entity *base = mObjectLists[0].mEntities[i]; base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if (mVisibilityFlags != 0) @@ -111,9 +119,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if(mVisibilityFlags != 0) @@ -121,15 +129,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor part->setRenderQueueGroup(RQG_Alpha); } - std::vector skelnames(1, smodel); - if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); - else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); - if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - setAnimationSources(skelnames); - forceUpdate(); } From 7fcaffefb09dc8f9a95660e9513ef88540d71b3c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Apr 2013 03:13:25 +0200 Subject: [PATCH 1080/1483] Fixed travel window to use the rotation part of ESM::Position --- apps/openmw/mwgui/travelwindow.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 8eaa0d8c62..8389db0679 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -141,21 +141,22 @@ namespace MWGui int x,y; bool interior = _sender->getUserString("interior") == "y"; MWBase::Environment::get().getWorld()->positionToIndex(pos.pos[0],pos.pos[1],x,y); - MWWorld::CellStore* cell; - if(interior) cell = MWBase::Environment::get().getWorld()->getInterior(cellname); + if(interior) + MWBase::Environment::get().getWorld()->changeToInteriorCell(cellname, pos); else { - cell = MWBase::Environment::get().getWorld()->getExterior(x,y); - ESM::Position PlayerPos = player.getRefData().getPosition(); - float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) ); - int time = int(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); - for(int i = 0;i < time;i++) + ESM::Position playerPos = player.getRefData().getPosition(); + float d = Ogre::Vector3(pos.pos[0], pos.pos[1], 0).distance( + Ogre::Vector3(playerPos.pos[0], playerPos.pos[1], 0)); + int hours = static_cast(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); + for(int i = 0;i < hours;i++) { MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats (); } - MWBase::Environment::get().getWorld()->advanceTime(time); + MWBase::Environment::get().getWorld()->advanceTime(hours); + + MWBase::Environment::get().getWorld()->changeToExteriorCell(pos); } - MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); MWWorld::Class::get(player).adjustPosition(player); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); From 972481f63f7ef724364b6cf9672aac50fc558788 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 15 Apr 2013 16:45:53 +0200 Subject: [PATCH 1081/1483] Working rotate, rotateworld --- apps/openmw/mwbase/windowmanager.hpp | 2 + apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 + apps/openmw/mwscript/docs/vmformat.txt | 4 +- .../mwscript/transformationextensions.cpp | 56 +++++++++++++++++-- apps/openmw/mwworld/worldimp.cpp | 6 ++ apps/openmw/mwworld/worldimp.hpp | 2 + 8 files changed, 73 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 976d7d84c1..b34117df29 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,6 +251,8 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; + + virtual int getFPS() const = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39e985890a..94a30d759b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -230,6 +230,8 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; + virtual void localRotateObject (const MWWorld::Ptr& ptr, float rotation, Ogre::Vector3 axis) = 0; + virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f994683a66..b3a080bf25 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1200,3 +1200,8 @@ void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); } + +int WindowManager::getFPS() const +{ + return mFPS; +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3c9fc586a3..3a7296b5ba 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -248,6 +248,8 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); + virtual int getFPS() const; + private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7810c2874b..b7ee2d31c6 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -320,5 +320,7 @@ op 0x20001fd: IsWerewolf op 0x20001fe: IsWerewolf, explicit reference op 0x20001ff: Rotate op 0x2000200: Rotate, explicit reference +op 0x2000201: RotateWorld +op 0x2000202: RotateWorld, explicit reference -opcodes 0x2000201-0x3ffffff unused +opcodes 0x2000203-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 922353974d..41bacf1106 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -13,6 +13,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -549,11 +550,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = R()(runtime); + const MWWorld::Ptr& ptr = R()(runtime); std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why (probably framerate) + Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; @@ -562,19 +563,22 @@ namespace MWScript { objRot[0]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_X));; + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { objRot[1]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Y)); + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { objRot[2]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Z)); + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } else @@ -582,6 +586,43 @@ namespace MWScript } }; + template + class OpRotateWorld : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + runtime.pop(); + + float *objRot = ptr.getRefData().getPosition().rot; + + float ax = Ogre::Radian(objRot[0]).valueDegrees(); + float ay = Ogre::Radian(objRot[1]).valueDegrees(); + float az = Ogre::Radian(objRot[2]).valueDegrees(); + + if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + } + else if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -610,6 +651,8 @@ namespace MWScript const int opcodeModScaleExplicit = 0x20001e4; const int opcodeRotate = 0x20001ff; const int opcodeRotateExplicit = 0x2000200; + const int opcodeRotateWorld = 0x2000201; + const int opcodeRotateWorldExplicit = 0x2000202; void registerExtensions (Compiler::Extensions& extensions) { @@ -628,6 +671,7 @@ namespace MWScript extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); + extensions.registerInstruction("rotateworld","cf",opcodeRotateWorld,opcodeRotateWorldExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -659,6 +703,8 @@ namespace MWScript interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); interpreter.installSegment5(opcodeRotate,new OpRotate); interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); + interpreter.installSegment5(opcodeRotateWorld,new OpRotateWorld); + interpreter.installSegment5(opcodeRotateWorldExplicit,new OpRotateWorld); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 11ccd8f2fc..c5ebbb306f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -826,6 +826,12 @@ namespace MWWorld } } + void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) + { + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + mPhysics->rotateObject(ptr); + } + void World::adjustPosition(const Ptr &ptr) { Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7b12babee9..59a359b6b7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -254,6 +254,8 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + virtual void localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis); + virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. From 763308868d501bc7bd7102d6a442855f8c155f1b Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 15 Apr 2013 17:45:18 +0200 Subject: [PATCH 1082/1483] Fixed rotation speed --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ----- apps/openmw/mwgui/windowmanagerimp.hpp | 2 -- apps/openmw/mwscript/transformationextensions.cpp | 5 ++--- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b34117df29..976d7d84c1 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,8 +251,6 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; - - virtual int getFPS() const = 0; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b3a080bf25..f994683a66 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1200,8 +1200,3 @@ void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); } - -int WindowManager::getFPS() const -{ - return mFPS; -} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3a7296b5ba..3c9fc586a3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -248,8 +248,6 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); - virtual int getFPS() const; - private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 41bacf1106..8ac5a7802a 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -13,7 +13,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -554,7 +553,7 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; @@ -597,7 +596,7 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; From 1b1f9f7921d91bc2c2c853cfc0b0f5c71fba0574 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 18:55:28 -0700 Subject: [PATCH 1083/1483] Allow multiple ObjectLists to be created for Animations. addObjectList may not currently be called outside of the related constructor. --- apps/openmw/mwrender/activatoranimation.cpp | 13 ++-- apps/openmw/mwrender/animation.cpp | 80 +++++++++++++-------- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 17 +++-- apps/openmw/mwrender/npcanimation.cpp | 39 +++------- components/nifogre/ogrenifloader.cpp | 7 +- components/nifogre/ogrenifloader.hpp | 2 +- 7 files changed, 82 insertions(+), 78 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 27ddce339d..1f9a2e23c9 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -24,12 +24,13 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->mBase->mModel; + const std::string name = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), name, false); + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,9 +39,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Misc); part->setRenderQueueGroup(RQG_Alpha); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30bcd3c4c3..979046ea07 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -36,7 +36,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) - , mAccumulate(Ogre::Vector3::ZERO) + , mAccumulate(0.0f) , mLastPosition(0.0f) , mCurrentControllers(NULL) , mCurrentKeys(NULL) @@ -62,20 +62,24 @@ Animation::~Animation() } -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) +void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly) { - assert(!mInsert); - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectLists.resize(1); - - mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectLists[0].mSkelBase) + if(!mInsert) { - mSkelBase = mObjectLists[0].mSkelBase; + mInsert = node->createChildSceneNode(); + assert(mInsert); + } + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + NifOgre::ObjectList &objlist = mObjectLists.back(); + if(objlist.mSkelBase) + { + if(!mSkelBase) + mSkelBase = objlist.mSkelBase; + + Ogre::AnimationStateSet *aset = objlist.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -87,11 +91,28 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = objlist.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + if(mSkelBase != objlist.mSkelBase) + { + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(!dstval) continue; + + const Ogre::String &trgtname = dstval->getNode()->getName(); + if(!baseinst->hasBone(trgtname)) continue; + + Ogre::Bone *bone = baseinst->getBone(trgtname); + dstval->setNode(bone); + } + } + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -120,14 +141,14 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model break; } } - - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { - if(mObjectLists[0].mControllers[i].getSource().isNull()) - mObjectLists[0].mControllers[i].setSource(ctrlval); + if(objlist.mControllers[i].getSource().isNull()) + objlist.mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectLists[0].mControllers; + + if(!mCurrentControllers || (*mCurrentControllers).size() == 0) + mCurrentControllers = &objlist.mControllers; } @@ -399,9 +420,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); + Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); + mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; @@ -456,20 +478,22 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mCurrentControllers->size();i++) + + for(size_t i = 0;i < (*mCurrentControllers).size();i++) (*mCurrentControllers)[i].update(); if(mSkelBase) { - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); - for(size_t i = 0;i < mObjectLists.size();i++) + const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - Ogre::Entity *ent = mObjectLists[i].mSkelBase; + Ogre::Entity *ent = iter->mSkelBase; if(!ent) continue; - Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); - if(skelsrc != skeldst) - updateSkeletonInstance(skelsrc, skeldst); + Ogre::SkeletonInstance *inst = ent->getSkeleton(); + if(baseinst != inst) + updateSkeletonInstance(baseinst, inst); + // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. ent->getAllAnimationStates()->_notifyDirty(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3c7433db98..79262f3c50 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -81,7 +81,7 @@ protected: bool handleEvent(float time, const std::string &evt); - void createObjectList(Ogre::SceneNode *node, const std::string &model); + void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); public: diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7084974b8c..a48b8da9f8 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,15 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - std::vector names; if((ref->mBase->mFlags&ESM::Creature::Biped)) - names.push_back("meshes\\base_anim.nif"); - names.push_back(model); + addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); - createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), model, false); + + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -43,11 +43,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a713ae79e1..3ef357440a 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,38 +96,13 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - std::vector skelnames(1, smodel); + addObjectList(node, smodel, true); if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); + addObjectList(node, "meshes\\base_anim_female.nif", true); else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); + addObjectList(node, "meshes\\argonian_swimkna.nif", true); if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - - createObjectList(node, smodel/*skelnames*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) - { - Ogre::Entity *base = mObjectLists[0].mEntities[i]; - - base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if (mVisibilityFlags != 0) - base->setVisibilityFlags(mVisibilityFlags); - - for(unsigned int j=0; j < base->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = base->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) - { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; - - part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if(mVisibilityFlags != 0) - part->setVisibilityFlags(mVisibilityFlags); - part->setRenderQueueGroup(RQG_Alpha); - } + addObjectList(node, "meshes\\"+mNpc->mModel, true); forceUpdate(); } @@ -406,14 +381,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; if(!ent) continue; - updateSkeletonInstance(skelsrc, ent->getSkeleton()); + updateSkeletonInstance(baseinst, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); } + return ret; } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 69f14b663d..04cdb142f6 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -800,12 +800,15 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena } -ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string name, const std::string &group) +ObjectList Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group, 0xC0000000); + + if(objectlist.mSkelBase) + parentNode->attachObject(objectlist.mSkelBase); return objectlist; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index fa5182aeaa..e3bb550640 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -69,7 +69,7 @@ public: std::string name, const std::string &group="General"); - static ObjectList createObjectBase(Ogre::SceneManager *sceneMgr, + static ObjectList createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); }; From 4ce98e9bd65ff2035e2f36e89a90cb6f892472fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 20:37:10 -0700 Subject: [PATCH 1084/1483] Store iterators for start and stop keys --- apps/openmw/mwrender/animation.cpp | 51 ++++++++++++------------------ apps/openmw/mwrender/animation.hpp | 7 ++-- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 979046ea07..11876a2473 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -38,11 +38,10 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) + , mCurrentAnim(NULL) , mCurrentControllers(NULL) , mCurrentKeys(NULL) - , mCurrentAnim(NULL) , mCurrentTime(0.0f) - , mStopTime(0.0f) , mPlaying(false) , mLooping(false) , mAnimVelocity(0.0f) @@ -313,35 +312,26 @@ Ogre::Vector3 Animation::updatePosition() void Animation::reset(const std::string &start, const std::string &stop) { - mNextKey = mCurrentKeys->begin(); + mStartKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != start) - mNextKey++; - if(mNextKey != mCurrentKeys->end()) - mCurrentTime = mNextKey->first; + while(mStartKey != mCurrentKeys->end() && mStartKey->second != start) + mStartKey++; + if(mStartKey != mCurrentKeys->end()) + mCurrentTime = mStartKey->first; else { - mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != "start") - mNextKey++; - if(mNextKey != mCurrentKeys->end()) - mCurrentTime = mNextKey->first; - else - { - mNextKey = mCurrentKeys->begin(); - mCurrentTime = 0.0f; - } + mStartKey = mCurrentKeys->begin(); + mCurrentTime = mStartKey->first; } + mNextKey = mStartKey; if(stop.length() > 0) { - NifOgre::TextKeyMap::const_iterator stopKey = mNextKey; - while(stopKey != mCurrentKeys->end() && stopKey->second != stop) - stopKey++; - if(stopKey != mCurrentKeys->end()) - mStopTime = stopKey->first; - else - mStopTime = mCurrentAnim->getLength(); + mStopKey = mStartKey; + while(mStopKey != mCurrentKeys->end() && mStopKey->second != stop) + mStopKey++; + if(mStopKey == mCurrentKeys->end()) + mStopKey--; } if(mNonAccumRoot) @@ -390,7 +380,7 @@ bool Animation::handleEvent(float time, const std::string &evt) { if(mLooping) { - reset("loop start", ""); + reset("loop start"); if(mCurrentTime >= time) return false; } @@ -400,7 +390,7 @@ bool Animation::handleEvent(float time, const std::string &evt) { if(mLooping) { - reset("loop start", ""); + reset("loop start"); if(mCurrentTime >= time) return false; return true; @@ -455,13 +445,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) while(mCurrentAnim && mPlaying) { float targetTime = mCurrentTime + timepassed; - if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) + if(mNextKey->first > targetTime) { - mCurrentTime = std::min(mStopTime, targetTime); + mCurrentTime = targetTime; if(mNonAccumRoot) movement += updatePosition(); - mPlaying = (mLooping || mStopTime > mCurrentTime); - timepassed = targetTime - mCurrentTime; break; } @@ -472,7 +460,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) mCurrentTime = time; if(mNonAccumRoot) movement += updatePosition(); - mPlaying = (mLooping || mStopTime > mCurrentTime); + + mPlaying = (mLooping || mStopKey->first > mCurrentTime); timepassed = targetTime - mCurrentTime; if(!handleEvent(time, evt)) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 79262f3c50..f8ddceeaa3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -50,13 +50,14 @@ protected: Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; + Ogre::Animation *mCurrentAnim; std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; - Ogre::Animation *mCurrentAnim; float mCurrentTime; - float mStopTime; bool mPlaying; bool mLooping; @@ -77,7 +78,7 @@ protected: * moving anything, and set the end time to the specified stop marker. If * the marker is not found, it resets to the beginning or end respectively. */ - void reset(const std::string &start, const std::string &stop); + void reset(const std::string &start, const std::string &stop=std::string()); bool handleEvent(float time, const std::string &evt); From 36170c5374402f06b49bcf63d7c856572072ebda Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Apr 2013 01:20:32 -0700 Subject: [PATCH 1085/1483] Use flag enums instead of hard-coded hex values --- components/nif/node.hpp | 18 +++++++------ components/nifbullet/bulletnifloader.cpp | 6 ++--- components/nifogre/ogrenifloader.cpp | 32 +++++++++++++----------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 9c345baab2..917bc8add3 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -128,13 +128,17 @@ struct NiNode : Node NodeList children; NodeList effects; - /* Known NiNode flags: - 0x01 hidden - 0x02 use mesh for collision - 0x04 use bounding box for collision (?) - 0x08 unknown, but common - 0x20, 0x40, 0x80 unknown - */ + enum Flags { + Flag_Hidden = 0x0001, + Flag_MeshCollision = 0x0002, + Flag_BBoxCollision = 0x0004 + }; + enum BSAnimFlags { + AnimFlag_AutoPlay = 0x0020 + }; + enum BSParticleFlags { + ParticleFlag_AutoPlay = 0x0020 + }; void read(NIFStream *nif) { diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 6bd43f6e35..a3eff95c3e 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -255,9 +255,9 @@ void ManualBulletShapeLoader::handleNiTriShape(btTriangleMesh* mesh, const Nif:: assert(shape != NULL); // 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 + bool hidden = (flags&Nif::NiNode::Flag_Hidden) != 0; + bool collide = (flags&Nif::NiNode::Flag_MeshCollision) != 0; + bool bbcollide = (flags&Nif::NiNode::Flag_BBoxCollision) != 0; // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 04cdb142f6..2e77adb082 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -394,7 +394,7 @@ class NIFObjectLoader NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); Ogre::Entity *entity = sceneMgr->createEntity(fullname); - entity->setVisible(!(flags&0x01)); + entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); objectlist.mEntities.push_back(entity); if(objectlist.mSkelBase) @@ -417,10 +417,11 @@ class NIFObjectLoader const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -551,10 +552,11 @@ class NIFObjectLoader objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - Ogre::ControllerValueRealPtr srcval((partflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -568,7 +570,7 @@ class NIFObjectLoader objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - partsys->setVisible(!(flags&0x01)); + partsys->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); objectlist.mParticles.push_back(partsys); } @@ -627,10 +629,11 @@ class NIFObjectLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -641,10 +644,11 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } From 518cb0e3b7a181462bb7044ae966a9bcf18659c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 16 Apr 2013 12:12:04 +0200 Subject: [PATCH 1086/1483] added another abstraction layer to ID access in IdCollection --- apps/opencs/model/world/idcollection.hpp | 123 +++++++++++++---------- 1 file changed, 72 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 4afe9cbaab..7052b300e4 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -79,8 +79,29 @@ namespace CSMWorld virtual void load (ESM::ESMReader& reader, bool base) = 0; }; - ///< \brief Collection of ID-based records + ///< \brief Access to ID field in records template + struct IdAccessor + { + std::string& getId (ESXRecordT& record); + + const std::string getId (const ESXRecordT& record) const; + }; + + template + std::string& IdAccessor::getId (ESXRecordT& record) + { + return record.mId; + } + + template + const std::string IdAccessor::getId (const ESXRecordT& record) const + { + return record.mId; + } + + ///< \brief Collection of ID-based records + template > class IdCollection : public IdCollectionBase { std::vector > mRecords; @@ -150,21 +171,21 @@ namespace CSMWorld void addColumn (Column *column); }; - template - IdCollection::IdCollection() + template + IdCollection::IdCollection() {} - template - IdCollection::~IdCollection() + template + IdCollection::~IdCollection() { for (typename std::vector *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) delete *iter; } - template - void IdCollection::add (const ESXRecordT& record) + template + void IdCollection::add (const ESXRecordT& record) { - std::string id = Misc::StringUtils::lowerCase(record.mId); + std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record)); std::map::iterator iter = mIndex.find (id); @@ -183,20 +204,20 @@ namespace CSMWorld } } - template - int IdCollection::getSize() const + template + int IdCollection::getSize() const { return mRecords.size(); } - template - std::string IdCollection::getId (int index) const + template + std::string IdCollection::getId (int index) const { - return mRecords.at (index).get().mId; + return IdAccessorT().getId (mRecords.at (index).get()); } - template - int IdCollection::getIndex (const std::string& id) const + template + int IdCollection::getIndex (const std::string& id) const { int index = searchId (id); @@ -206,38 +227,38 @@ namespace CSMWorld return index; } - template - int IdCollection::getColumns() const + template + int IdCollection::getColumns() const { return mColumns.size(); } - template - QVariant IdCollection::getData (int index, int column) const + template + QVariant IdCollection::getData (int index, int column) const { return mColumns.at (column)->get (mRecords.at (index)); } - template - void IdCollection::setData (int index, int column, const QVariant& data) + template + void IdCollection::setData (int index, int column, const QVariant& data) { return mColumns.at (column)->set (mRecords.at (index), data); } - template - const ColumnBase& IdCollection::getColumn (int column) const + template + const ColumnBase& IdCollection::getColumn (int column) const { return *mColumns.at (column); } - template - void IdCollection::addColumn (Column *column) + template + void IdCollection::addColumn (Column *column) { mColumns.push_back (column); } - template - void IdCollection::merge() + template + void IdCollection::merge() { for (typename std::vector >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter) iter->merge(); @@ -245,16 +266,16 @@ namespace CSMWorld purge(); } - template - void IdCollection::purge() + template + void IdCollection::purge() { mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(), std::mem_fun_ref (&Record::isErased) // I want lambda :( ), mRecords.end()); } - template - void IdCollection::removeRows (int index, int count) + template + void IdCollection::removeRows (int index, int count) { mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count); @@ -278,17 +299,17 @@ namespace CSMWorld } } - template - void IdCollection::appendBlankRecord (const std::string& id) + template + void IdCollection::appendBlankRecord (const std::string& id) { ESXRecordT record; - record.mId = id; + IdAccessorT().getId (record) = id; record.blank(); add (record); } - template - int IdCollection::searchId (const std::string& id) const + template + int IdCollection::searchId (const std::string& id) const { std::string id2 = Misc::StringUtils::lowerCase(id); @@ -300,28 +321,28 @@ namespace CSMWorld return iter->second; } - template - void IdCollection::replace (int index, const RecordBase& record) + template + void IdCollection::replace (int index, const RecordBase& record) { mRecords.at (index) = dynamic_cast&> (record); } - template - void IdCollection::appendRecord (const RecordBase& record) + template + void IdCollection::appendRecord (const RecordBase& record) { mRecords.push_back (dynamic_cast&> (record)); mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (getId (record)), mRecords.size()-1)); } - template - std::string IdCollection::getId (const RecordBase& record) const + template + std::string IdCollection::getId (const RecordBase& record) const { const Record& record2 = dynamic_cast&> (record); - return (record2.isModified() ? record2.mModified : record2.mBase).mId; + return IdAccessorT().getId (record2.isModified() ? record2.mModified : record2.mBase); } - template - void IdCollection::load (ESM::ESMReader& reader, bool base) + template + void IdCollection::load (ESM::ESMReader& reader, bool base) { std::string id = reader.getHNOString ("NAME"); @@ -351,10 +372,10 @@ namespace CSMWorld else { ESXRecordT record; - record.mId = id; + IdAccessorT().getId (record) = id; record.load (reader); - int index = searchId (record.mId); + int index = searchId (IdAccessorT().getId (record)); if (index==-1) { @@ -378,15 +399,15 @@ namespace CSMWorld } } - template - const Record& IdCollection::getRecord (const std::string& id) const + template + const Record& IdCollection::getRecord (const std::string& id) const { int index = getIndex (id); return mRecords.at (index); } - template - const Record& IdCollection::getRecord (int index) const + template + const Record& IdCollection::getRecord (int index) const { return mRecords.at (index); } From 1e92ffc3147229b9d1b08e972b4372f7b8ca9f49 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:17:19 +0200 Subject: [PATCH 1087/1483] Added rotation layer --- .../mwscript/transformationextensions.cpp | 27 +++++++++---------- apps/openmw/mwworld/refdata.cpp | 12 ++++++++- apps/openmw/mwworld/refdata.hpp | 10 +++++++ apps/openmw/mwworld/scene.cpp | 7 +++++ apps/openmw/mwworld/worldimp.cpp | 6 +++-- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8ac5a7802a..e2d701268b 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -102,6 +102,11 @@ namespace MWScript } else throw std::runtime_error ("invalid ration axis: " + axis); + + //Local rotations clear + ptr.getRefData().getLocalRotation().rot[0]=0; + ptr.getRefData().getLocalRotation().rot[1]=0; + ptr.getRefData().getLocalRotation().rot[2]=0; } }; @@ -148,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]+ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]+ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]+ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -556,27 +561,19 @@ namespace MWScript Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float *objRot = ptr.getRefData().getPosition().rot; - if (axis == "x") { - objRot[0]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) - MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); + ptr.getRefData().getLocalRotation().rot[0]+=rotation; + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { - objRot[1]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) + ptr.getRefData().getLocalRotation().rot[1]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { - objRot[2]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) + ptr.getRefData().getLocalRotation().rot[2]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 4be2878104..db565c4513 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -19,6 +19,7 @@ namespace MWWorld mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; + mLocalRotation = refData.mLocalRotation; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -34,7 +35,11 @@ namespace MWWorld RefData::RefData (const ESM::CellRef& cellRef) : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0) - {} + { + mLocalRotation.rot[0]=0; + mLocalRotation.rot[1]=0; + mLocalRotation.rot[2]=0; + } RefData::RefData (const RefData& refData) : mBaseNode(0), mCustomData (0) @@ -141,6 +146,11 @@ namespace MWWorld return mPosition; } + LocalRotation& RefData::getLocalRotation() + { + return mLocalRotation; + } + void RefData::setCustomData (CustomData *data) { delete mCustomData; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 3a6e0fc9fd..c3aa647ec2 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,6 +5,8 @@ #include "../mwscript/locals.hpp" +#include + namespace Ogre { class SceneNode; @@ -18,6 +20,10 @@ namespace ESM namespace MWWorld { + struct LocalRotation{ + float rot[3]; + }; + class CustomData; class RefData @@ -34,6 +40,8 @@ namespace MWWorld ESM::Position mPosition; + LocalRotation mLocalRotation; + CustomData *mCustomData; void copy (const RefData& refData); @@ -78,6 +86,8 @@ namespace MWWorld ESM::Position& getPosition(); + LocalRotation& getLocalRotation(); + void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \æ data is /// transferred to this. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 439f761311..b11b59ac62 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -50,6 +50,13 @@ namespace rendering.addObject(ptr); class_.insertObject(ptr, physics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + + //To keep local-rotations + const float *local = ptr.getRefData().getLocalRotation().rot; + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[0], Ogre::Vector3::UNIT_X); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[1], Ogre::Vector3::UNIT_Y); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[2], Ogre::Vector3::UNIT_Z); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); class_.adjustPosition(ptr); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 52d0d953a0..69bcad619d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -826,8 +826,10 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) { - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); - mPhysics->rotateObject(ptr); + if (ptr.getRefData().getBaseNode() != 0) { + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + mPhysics->rotateObject(ptr); + } } void World::adjustPosition(const Ptr &ptr) From 1fd59d0ce0c63e893f6203a723579d25dc3ec7c9 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:21:54 +0200 Subject: [PATCH 1088/1483] Removed useless include --- apps/openmw/mwworld/refdata.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index c3aa647ec2..77ceb3721a 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,8 +5,6 @@ #include "../mwscript/locals.hpp" -#include - namespace Ogre { class SceneNode; From e3a9f73eb6008159b3ba1fa1fa15451050360407 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:40:34 +0200 Subject: [PATCH 1089/1483] Improved getangle script behaviour --- apps/openmw/mwscript/transformationextensions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index e2d701268b..beb6c3d8c1 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -153,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]+ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]+ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]+ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); } else throw std::runtime_error ("invalid ration axis: " + axis); From 60fadaeaf0368df6c6bafafbabe24a233a74d124 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Tue, 16 Apr 2013 20:16:22 -0400 Subject: [PATCH 1090/1483] Cleaned up includes in implementation files --- apps/openmw/mwgui/alchemywindow.cpp | 2 -- apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/birth.cpp | 2 -- apps/openmw/mwgui/charactercreation.cpp | 2 -- apps/openmw/mwgui/class.cpp | 5 ----- apps/openmw/mwgui/companionwindow.cpp | 1 - apps/openmw/mwgui/confirmationdialog.cpp | 5 ----- apps/openmw/mwgui/console.cpp | 6 ------ apps/openmw/mwgui/container.cpp | 12 ------------ apps/openmw/mwgui/countdialog.cpp | 3 --- apps/openmw/mwgui/cursor.cpp | 2 -- apps/openmw/mwgui/dialogue.cpp | 9 +-------- apps/openmw/mwgui/formatting.cpp | 1 - apps/openmw/mwgui/hud.cpp | 10 ---------- apps/openmw/mwgui/inventorywindow.cpp | 13 ------------- apps/openmw/mwgui/journalwindow.cpp | 3 --- apps/openmw/mwgui/levelupdialog.cpp | 2 -- apps/openmw/mwgui/loadingscreen.cpp | 9 --------- apps/openmw/mwgui/mainmenu.cpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 4 ---- apps/openmw/mwgui/merchantrepair.cpp | 3 --- apps/openmw/mwgui/quickkeysmenu.cpp | 4 ---- apps/openmw/mwgui/race.cpp | 6 ------ apps/openmw/mwgui/review.cpp | 6 ------ apps/openmw/mwgui/settingswindow.cpp | 6 ------ apps/openmw/mwgui/soulgemdialog.cpp | 1 - apps/openmw/mwgui/spellbuyingwindow.cpp | 4 ---- apps/openmw/mwgui/spellcreationdialog.cpp | 8 -------- apps/openmw/mwgui/spellicons.cpp | 5 ----- apps/openmw/mwgui/spellwindow.cpp | 8 -------- apps/openmw/mwgui/statswindow.cpp | 6 ------ apps/openmw/mwgui/tooltips.cpp | 7 ------- apps/openmw/mwgui/tradewindow.cpp | 1 - apps/openmw/mwgui/travelwindow.cpp | 7 ------- apps/openmw/mwgui/waitdialog.cpp | 4 ---- apps/openmw/mwgui/widgets.cpp | 2 -- apps/openmw/mwgui/windowbase.cpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 23 +---------------------- apps/openmw/mwgui/windowpinnablebase.cpp | 2 -- 39 files changed, 2 insertions(+), 196 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index a6121c234c..24a4e205bf 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -8,8 +8,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/containerstore.hpp" namespace { diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 655a832c17..9189e4a631 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -10,7 +10,6 @@ namespace MWGui { - class AlchemyWindow : public WindowBase, public ContainerBase { public: diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 133bbd32fb..9c3ebdc7dc 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -3,8 +3,6 @@ #include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 0dd6502c6c..28f6d13ee2 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -5,8 +5,6 @@ #include "class.hpp" #include "birth.hpp" #include "review.hpp" -#include "dialogue.hpp" -#include "mode.hpp" #include "inventorywindow.hpp" #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 6edad9e83b..e4d32c933b 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -1,11 +1,6 @@ #include "class.hpp" -#include - #include -#include - -#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 0a20c471ab..22afc42f6d 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -2,7 +2,6 @@ #include -#include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 904468f886..f431f2f64c 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -1,10 +1,5 @@ #include "confirmationdialog.hpp" -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - namespace MWGui { ConfirmationDialog::ConfirmationDialog() : diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 1aebe57da2..bd1b0fe7ab 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -1,13 +1,7 @@ - #include "console.hpp" -#include -#include - #include -#include "../mwworld/esmstore.hpp" - #include "../mwscript/extensions.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 8ee4754a32..d15a5acd3e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -1,11 +1,5 @@ #include "container.hpp" -#include -#include -#include -#include -#include - #include #include "../mwbase/environment.hpp" @@ -13,15 +7,9 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwclass/container.hpp" - -#include "widgets.hpp" #include "countdialog.hpp" #include "tradewindow.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index d017cc1986..fe5122455c 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -2,9 +2,6 @@ #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - namespace MWGui { CountDialog::CountDialog() : diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index b0d164bedf..c069eca15a 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -2,13 +2,11 @@ #include #include -#include #include #include #include - namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index f3c11752e8..392f641264 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -1,18 +1,11 @@ #include "dialogue.hpp" -#include -#include - -#include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 7f28e9e17d..b21b903bde 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -3,7 +3,6 @@ #include #include "../mwscript/interpretercontext.hpp" -#include "../mwworld/ptr.hpp" #include #include diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 84526a28dd..988bcfc241 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,24 +1,14 @@ #include "hud.hpp" -#include - -#include -#include - #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwgui/widgets.hpp" - #include "inventorywindow.hpp" -#include "container.hpp" #include "console.hpp" #include "spellicons.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 40c228fd5a..e5e20b778b 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,28 +1,15 @@ #include "inventorywindow.hpp" -#include -#include -#include -#include - #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/containerstore.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/inventorystore.hpp" -#include "widgets.hpp" #include "bookwindow.hpp" #include "scrollwindow.hpp" #include "spellwindow.hpp" diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 35a687cc4a..23588a4afa 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -4,9 +4,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/soundmanager.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwdialogue/journalentry.hpp" namespace { diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index fc1317e908..5857db4d2e 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -8,12 +8,10 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/fallback.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/stat.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 858c3f36ec..3b341574d9 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -1,25 +1,16 @@ #include "loadingscreen.hpp" #include -#include #include #include -#include - - -#include #include #include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include - - namespace MWGui { diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 5402d35428..ebd31d92cf 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -3,7 +3,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 17834be937..1ac1c24480 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -2,12 +2,8 @@ #include -#include -#include #include -#include - #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 53148cb3f0..a98051c287 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -9,10 +9,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/containerstore.hpp" -#include "../mwworld/class.hpp" -#include "list.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 2deb37d301..a44f1791c4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -2,13 +2,9 @@ #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwworld/player.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" #include "../mwgui/inventorywindow.hpp" #include "../mwgui/bookwindow.hpp" diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9a0d8a029f..c031ad6b68 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -1,19 +1,13 @@ #include "race.hpp" -#include -#include - #include #include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "widgets.hpp" #include "tooltips.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 562bf97748..31f5d737b9 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -1,17 +1,11 @@ #include "review.hpp" -#include - -#include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "widgets.hpp" #include "tooltips.hpp" #undef min diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 93b82e3745..39ee4e01d0 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1,24 +1,18 @@ #include "settingswindow.hpp" #include -#include #include -#include #include #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwrender/renderingmanager.hpp" - #include "confirmationdialog.hpp" namespace diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index 4530a13d0b..b95eec0b67 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -1,6 +1,5 @@ #include "soulgemdialog.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "messagebox.hpp" diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 7d634df8d6..cb20075650 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -1,7 +1,5 @@ #include "spellbuyingwindow.hpp" -#include - #include #include "../mwbase/environment.hpp" @@ -11,9 +9,7 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index e1df9f9cd1..45cf1b0aaa 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -4,22 +4,14 @@ #include "../mwbase/windowmanager.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/class.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" - #include "tooltips.hpp" -#include "widgets.hpp" #include "class.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 206db51ed0..e762cc6105 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -1,9 +1,5 @@ #include "spellicons.hpp" -#include -#include -#include - #include #include "../mwbase/world.hpp" @@ -14,7 +10,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwmechanics/activespells.hpp" #include "../mwmechanics/creaturestats.hpp" #include "tooltips.hpp" diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d07f9ca542..bd1fef12b3 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -1,22 +1,14 @@ #include "spellwindow.hpp" -#include #include #include -#include "../mwworld/esmstore.hpp" - -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" #include "spellicons.hpp" diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index a00ec167da..3439ff31ce 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -1,14 +1,9 @@ #include "statswindow.hpp" -#include -#include -#include - #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" @@ -18,7 +13,6 @@ #include "tooltips.hpp" - using namespace MWGui; const int StatsWindow::sLineHeight = 18; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2250ffd0b5..b72d27aeae 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -2,18 +2,11 @@ #include -#include - -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/class.hpp" - #include "mapwindow.hpp" -#include "widgets.hpp" #include "inventorywindow.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f3f226974e..23bb6554f6 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -9,7 +9,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 8eaa0d8c62..780ffa0569 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -1,22 +1,15 @@ #include "travelwindow.hpp" -#include - #include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" - -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index a84b9203a9..ad2b4710cc 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,7 +1,5 @@ #include "waitdialog.hpp" -#include - #include #include @@ -11,9 +9,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/timestamp.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index dd3206ed65..e6c8b1d77d 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -9,8 +9,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/esmstore.hpp" - #undef min #undef max diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index c41bcb7ce6..cc74579abf 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,7 +1,5 @@ #include "windowbase.hpp" -#include - #include "../mwbase/windowmanager.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f2ded8813e..154234bee5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1,39 +1,20 @@ #include "windowmanagerimp.hpp" -#include -#include - -#include - #include #include -#include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/inputmanager.hpp" -#include "../mwworld/ptr.hpp" -#include "../mwworld/cellstore.hpp" - #include "console.hpp" #include "journalwindow.hpp" #include "charactercreation.hpp" -#include "textinput.hpp" -#include "review.hpp" #include "dialogue.hpp" #include "dialoguehistory.hpp" -#include "mapwindow.hpp" #include "statswindow.hpp" #include "messagebox.hpp" -#include "container.hpp" -#include "inventorywindow.hpp" #include "tooltips.hpp" #include "scrollwindow.hpp" #include "bookwindow.hpp" -#include "list.hpp" #include "hud.hpp" #include "mainmenu.hpp" #include "countdialog.hpp" @@ -48,17 +29,15 @@ #include "loadingscreen.hpp" #include "levelupdialog.hpp" #include "waitdialog.hpp" -#include "spellcreationdialog.hpp" #include "enchantingdialog.hpp" #include "trainingwindow.hpp" -#include "imagebutton.hpp" #include "exposedwindow.hpp" #include "cursor.hpp" -#include "spellicons.hpp" #include "merchantrepair.hpp" #include "repair.hpp" #include "soulgemdialog.hpp" #include "companionwindow.hpp" +#include "inventorywindow.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 56868306ac..53ba1b9fd6 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -1,7 +1,5 @@ #include "windowpinnablebase.hpp" -#include "../mwbase/windowmanager.hpp" - #include "exposedwindow.hpp" using namespace MWGui; From 3def2a0f453932c8fed8e83bc2654082e6ab0c46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Apr 2013 19:16:45 -0700 Subject: [PATCH 1091/1483] Treat the particle random values as the max differential --- components/nifogre/ogrenifloader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 2e77adb082..c5cc45ae9f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -433,11 +433,11 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, - partctrl->velocity+partctrl->velocityRandom); + emitter->setParticleVelocity(partctrl->velocity - partctrl->velocityRandom*0.5f, + partctrl->velocity + partctrl->velocityRandom*0.5f); emitter->setEmissionRate(partctrl->emitRate); - emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, - partctrl->lifetime+partctrl->lifetimeRandom); + emitter->setTimeToLive(partctrl->lifetime - partctrl->lifetimeRandom*0.5f, + partctrl->lifetime + partctrl->lifetimeRandom*0.5f); emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); From c1ec16986bc396bc611154d992cad25fe3dea503 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 17 Apr 2013 12:04:05 +0200 Subject: [PATCH 1092/1483] add cmake fix for compiling with binutils >= 2.23 which requires explicit linking for dl and Xt --- apps/launcher/CMakeLists.txt | 6 ++++++ apps/openmw/CMakeLists.txt | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index eb93d71e78..0c93474da9 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -102,3 +102,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(omwlauncher gcov) endif() + +# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream +if (UNIX AND NOT APPLE) +target_link_libraries(omwlauncher dl Xt) +endif() + diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3334e7865c..f4fdcb390e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -122,6 +122,12 @@ if (UNIX AND NOT APPLE) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) endif() +# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream +if (UNIX AND NOT APPLE) +target_link_libraries(openmw dl Xt) +endif() + + if(APPLE) find_library(CARBON_FRAMEWORK Carbon) find_library(COCOA_FRAMEWORK Cocoa) From 547f77031db127fae46b374c94fccc854d08b067 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Apr 2013 17:05:54 +0200 Subject: [PATCH 1093/1483] Fix crash when disabling objects in a previously loaded cell, then coming back to that cell and leaving again --- apps/openmw/mwrender/actors.cpp | 4 ++++ apps/openmw/mwworld/cellfunctors.hpp | 6 ++++-- apps/openmw/mwworld/scene.cpp | 29 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 644d3613bd..566b6fa81e 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -94,6 +94,9 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr) bool Actors::deleteObject (const MWWorld::Ptr& ptr) { + if (mAllActors.find(ptr) == mAllActors.end()) + return false; + mRendering->removeWaterRippleEmitter (ptr); delete mAllActors[ptr]; @@ -139,6 +142,7 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) Ogre::SceneNode *base = celliter->second; base->removeAndDestroyAllChildren(); mRend.getScene()->destroySceneNode(base); + mCellSceneNodes.erase(celliter); } } diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp index 8bba898ce7..4b1f70096a 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -13,8 +13,8 @@ namespace ESM namespace MWWorld { - /// List all (Ogre-)handles. - struct ListHandles + /// List all (Ogre-)handles, then reset RefData::mBaseNode to 0. + struct ListAndResetHandles { std::vector mHandles; @@ -23,6 +23,8 @@ namespace MWWorld Ogre::SceneNode* handle = data.getBaseNode(); if (handle) mHandles.push_back (handle); + + data.setBaseNode(0); return true; } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 439f761311..b9b0aa19c8 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -76,27 +76,28 @@ namespace MWWorld void Scene::unloadCell (CellStoreCollection::iterator iter) { std::cout << "Unloading cell\n"; - ListHandles functor; + ListAndResetHandles functor; - (*iter)->forEach(functor); + (*iter)->forEach(functor); { // silence annoying g++ warning for (std::vector::const_iterator iter2 (functor.mHandles.begin()); - iter2!=functor.mHandles.end(); ++iter2){ - Ogre::SceneNode* node = *iter2; + iter2!=functor.mHandles.end(); ++iter2) + { + Ogre::SceneNode* node = *iter2; mPhysics->removeObject (node->getName()); } + } - if ((*iter)->mCell->isExterior()) - { - ESM::Land* land = - MWBase::Environment::get().getWorld()->getStore().get().search( - (*iter)->mCell->getGridX(), - (*iter)->mCell->getGridY() - ); - if (land) - mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() ); - } + if ((*iter)->mCell->isExterior()) + { + ESM::Land* land = + MWBase::Environment::get().getWorld()->getStore().get().search( + (*iter)->mCell->getGridX(), + (*iter)->mCell->getGridY() + ); + if (land) + mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() ); } mRendering.removeCell(*iter); From 0341a9e7781342e321744e1976f2a1918521806d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Apr 2013 20:57:22 +0200 Subject: [PATCH 1094/1483] Fix a gcc 4.8 warning --- apps/openmw/mwrender/videoplayer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 2cbc85cd38..87ae8175de 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -788,8 +788,8 @@ void VideoState::decode_thread_loop(VideoState *self) // main decode loop while(!self->quit) { - if((self->audio_st >= 0 && self->audioq.size > MAX_AUDIOQ_SIZE) || - (self->video_st >= 0 && self->videoq.size > MAX_VIDEOQ_SIZE)) + if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) || + (self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE)) { boost::this_thread::sleep(boost::posix_time::milliseconds(10)); continue; From c519fc360ddaeb13872fd761c267123440a88b7e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 00:19:34 +0200 Subject: [PATCH 1095/1483] Move away from fixed record names for body parts --- apps/esmtool/record.cpp | 2 +- apps/openmw/mwgui/race.cpp | 132 +++++++------------------- apps/openmw/mwgui/race.hpp | 7 +- apps/openmw/mwrender/npcanimation.cpp | 109 +++++++++++++-------- components/esm/loadarmo.hpp | 4 +- components/esm/loadbody.cpp | 4 +- components/esm/loadbody.hpp | 6 +- 7 files changed, 118 insertions(+), 146 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e16ade6e24..b7cbbc4eaf 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -439,7 +439,7 @@ void Record::print() template<> void Record::print() { - std::cout << " Name: " << mData.mName << std::endl; + std::cout << " Race: " << mData.mRace << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Type: " << meshTypeLabel(mData.mData.mType) << " (" << (int)mData.mData.mType << ")" << std::endl; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index c031ad6b68..25bae999b5 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -24,36 +24,6 @@ int wrap(int index, int max) else return index; } - -int countParts(const std::string &part, const std::string &race, bool male) -{ - /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs - const MWWorld::Store &store = - MWBase::Environment::get().getWorld()->getStore().get(); - - std::string prefix = - "b_n_" + race + ((male) ? "_m_" : "_f_") + part; - - std::string suffix; - suffix.reserve(prefix.size() + 3); - - int count = -1; - do { - ++count; - suffix = "_" + (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - - if (count == 0 && part == "hair") { - count = -1; - do { - ++count; - suffix = (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - } - return count; -} } RaceDialog::RaceDialog() @@ -61,8 +31,6 @@ RaceDialog::RaceDialog() , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) - , mFaceCount(10) - , mHairCount(14) , mCurrentAngle(0) { // Centre dialog @@ -227,67 +195,28 @@ void RaceDialog::onSelectNextGender(MyGUI::Widget*) void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) { - do - mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); - while (!isFacePlayable()); + mFaceIndex = wrap(mFaceIndex - 1, mAvailableHeads.size()); updatePreview(); } void RaceDialog::onSelectNextFace(MyGUI::Widget*) { - do - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); - while (!isFacePlayable()); + mFaceIndex = wrap(mFaceIndex + 1, mAvailableHeads.size()); updatePreview(); } void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) { - do - mHairIndex = wrap(mHairIndex - 1, mHairCount); - while (!isHairPlayable()); + mHairIndex = wrap(mHairIndex - 1, mAvailableHairs.size()); updatePreview(); } void RaceDialog::onSelectNextHair(MyGUI::Widget*) { - do - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isHairPlayable()); + mHairIndex = wrap(mHairIndex + 1, mAvailableHairs.size()); updatePreview(); } -bool RaceDialog::isFacePlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(prefix + "head_" + headIndex) == 0) - return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -bool RaceDialog::isHairPlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - if (parts.search(prefix + "hair_" + hairIndex) == 0) - return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) { if (_index == MyGUI::ITEM_NONE) @@ -308,18 +237,41 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) updateSpellPowers(); } +void RaceDialog::getBodyParts (int part, std::vector& out) +{ + out.clear(); + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + for (MWWorld::Store::iterator it = store.begin(); it != store.end(); ++it) + { + const ESM::BodyPart& bodypart = *it; + if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) + continue; + if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) + continue; + if (bodypart.mData.mPart != static_cast(part)) + continue; + if (mGenderIndex != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + continue; + bool firstPerson = (bodypart.mId.size() >= 3) + && bodypart.mId[bodypart.mId.size()-3] == '1' + && bodypart.mId[bodypart.mId.size()-2] == 's' + && bodypart.mId[bodypart.mId.size()-1] == 't'; + if (firstPerson) + continue; + if (Misc::StringUtils::ciEqual(bodypart.mRace, mCurrentRaceId)) + out.push_back(bodypart.mId); + } +} + void RaceDialog::recountParts() { - mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); - mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + getBodyParts(ESM::BodyPart::MP_Hair, mAvailableHairs); + getBodyParts(ESM::BodyPart::MP_Head, mAvailableHeads); mFaceIndex = 0; mHairIndex = 0; - - while (!isHairPlayable()) - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isFacePlayable()) - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); } // update widget content @@ -330,21 +282,9 @@ void RaceDialog::updatePreview() record.mRace = mCurrentRaceId; record.setIsMale(mGenderIndex == 0); - std::string prefix = - "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); + record.mHead = mAvailableHeads[mFaceIndex]; + record.mHair = mAvailableHairs[mHairIndex]; - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - record.mHead = prefix + "head_" + headIndex; - record.mHair = prefix + "hair_" + hairIndex; - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(record.mHair) == 0) { - record.mHair = prefix + "hair" + hairIndex; - } mPreview->setPrototype(record); } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 893c4c90b6..1d48c67cdf 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -76,8 +76,10 @@ namespace MWGui void updatePreview(); void recountParts(); - bool isHairPlayable(); - bool isFacePlayable(); + void getBodyParts (int part, std::vector& out); + + std::vector mAvailableHeads; + std::vector mAvailableHairs; MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; @@ -90,7 +92,6 @@ namespace MWGui std::vector mSpellPowerItems; int mGenderIndex, mFaceIndex, mHairIndex; - int mFaceCount, mHairCount; std::string mCurrentRaceId; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 96220f47d0..ecc0869cc5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -305,56 +305,83 @@ void NpcAnimation::updateParts(bool forceupdate) if(mViewMode == VM_HeadOnly) return; - 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", "" } } - }; + std::map bodypartMap; + bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck; + bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest; + bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin; + bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand; + bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand; + bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist; + bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist; + bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm; + bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm; + bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm; + bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm; + bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot; + bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot; + bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle; + bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle; + bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee; + bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee; + bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg; + bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg; + bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail; - const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) + + const int Flag_Female = 0x01; + const int Flag_FirstPerson = 0x02; + + int flags = 0; + if (!mNpc->isMale()) + flags |= Flag_Female; + if (mViewMode == VM_FirstPerson) + flags |= Flag_FirstPerson; + + // Remember body parts so we only have to search through the store once for each race/gender/viewmode combination + static std::map< std::pair , std::vector > sRaceMapping; + std::string race = Misc::StringUtils::lowerCase(mNpc->mRace); + std::pair thisCombination = std::make_pair(race, flags); + if (sRaceMapping.find(thisCombination) == sRaceMapping.end()) { - if(mPartPriorities[PartTypeList[i].type] < 1) + sRaceMapping[thisCombination].resize(ESM::PRT_Count); + for (int i=0; i &partStore = store.get(); + + for (MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) { - const ESM::BodyPart *part = NULL; - const MWWorld::Store &partStore = store.get(); - - if(!mNpc->isMale()) + const ESM::BodyPart& bodypart = *it; + if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) + continue; + if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) { - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]+ext); - if(part == 0) - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]+ext); + continue; } - if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]+ext); - if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]+ext); + if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + continue; + if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace)) + continue; - if(part) - addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); + bool firstPerson = (bodypart.mId.size() >= 3) + && bodypart.mId[bodypart.mId.size()-3] == '1' + && bodypart.mId[bodypart.mId.size()-2] == 's' + && bodypart.mId[bodypart.mId.size()-1] == 't'; + if (firstPerson != (mViewMode == VM_FirstPerson)) + continue; + for (std::map::iterator bIt = bodypartMap.begin(); bIt != bodypartMap.end(); ++bIt ) + if (bIt->second == bodypart.mData.mPart) + sRaceMapping[thisCombination][bIt->first] = &*it; } } + + for (int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part) + { + const ESM::BodyPart* bodypart = sRaceMapping[thisCombination][part]; + if (mPartPriorities[part] < 1 && bodypart) + addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel); + } } NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index a94ae67353..c18b4486da 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -38,7 +38,9 @@ enum PartReferenceType PRT_RPauldron = 23, PRT_LPauldron = 24, PRT_Weapon = 25, - PRT_Tail = 26 + PRT_Tail = 26, + + PRT_Count = 27 }; // Reference to body parts diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 831ad8b641..e95a8a8603 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -9,13 +9,13 @@ namespace ESM void BodyPart::load(ESMReader &esm) { mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); + mRace = esm.getHNString("FNAM"); esm.getHNT(mData, "BYDT", 4); } void BodyPart::save(ESMWriter &esm) { esm.writeHNCString("MODL", mModel); - esm.writeHNCString("FNAM", mName); + esm.writeHNCString("FNAM", mRace); esm.writeHNT("BYDT", mData, 4); } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index c467b36251..3ad9b1b958 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -27,7 +27,9 @@ struct BodyPart MP_Knee = 11, MP_Upperleg = 12, MP_Clavicle = 13, - MP_Tail = 14 + MP_Tail = 14, + + MP_Count = 15 }; enum Flags @@ -52,7 +54,7 @@ struct BodyPart }; BYDTstruct mData; - std::string mId, mModel, mName; + std::string mId, mModel, mRace; void load(ESMReader &esm); void save(ESMWriter &esm); From 7eee86ab66f8b7fbd33e375418b6bdf44122dedf Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 17 Apr 2013 18:56:48 -0400 Subject: [PATCH 1096/1483] No more using namespace --- apps/openmw/mwgui/birth.cpp | 418 ++--- apps/openmw/mwgui/bookwindow.cpp | 261 +-- apps/openmw/mwgui/charactercreation.cpp | 1255 ++++++------- apps/openmw/mwgui/class.cpp | 1599 ++++++++-------- apps/openmw/mwgui/console.cpp | 31 +- apps/openmw/mwgui/container.cpp | 1220 ++++++------ apps/openmw/mwgui/dialogue.cpp | 912 ++++----- apps/openmw/mwgui/dialoguehistory.cpp | 104 +- apps/openmw/mwgui/formatting.cpp | 545 +++--- apps/openmw/mwgui/hud.cpp | 959 +++++----- apps/openmw/mwgui/list.cpp | 296 +-- apps/openmw/mwgui/mapwindow.cpp | 793 ++++---- apps/openmw/mwgui/messagebox.cpp | 747 ++++---- apps/openmw/mwgui/race.cpp | 822 ++++----- apps/openmw/mwgui/review.cpp | 658 +++---- apps/openmw/mwgui/scrollwindow.cpp | 128 +- apps/openmw/mwgui/statswindow.cpp | 1021 +++++----- apps/openmw/mwgui/textinput.cpp | 121 +- apps/openmw/mwgui/tooltips.cpp | 1416 +++++++------- apps/openmw/mwgui/widgets.cpp | 1676 ++++++++--------- apps/openmw/mwgui/windowmanagerimp.cpp | 2145 +++++++++++----------- apps/openmw/mwgui/windowpinnablebase.cpp | 39 +- 22 files changed, 8609 insertions(+), 8557 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 9c3ebdc7dc..9656067097 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -9,237 +9,239 @@ #include "widgets.hpp" -using namespace MWGui; -using namespace Widgets; - namespace { -bool sortBirthSigns(const std::pair& left, const std::pair& right) -{ - return left.second->mName.compare (right.second->mName) < 0; -} + bool sortBirthSigns(const std::pair& left, const std::pair& right) + { + return left.second->mName.compare (right.second->mName) < 0; + } } -BirthDialog::BirthDialog() - : WindowModal("openmw_chargen_birth.layout") +namespace MWGui { - // Centre dialog - center(); - getWidget(mSpellArea, "SpellArea"); + BirthDialog::BirthDialog() + : WindowModal("openmw_chargen_birth.layout") + { + // Centre dialog + center(); - getWidget(mBirthImage, "BirthsignImage"); + getWidget(mSpellArea, "SpellArea"); - getWidget(mBirthList, "BirthsignList"); - mBirthList->setScrollVisible(true); - mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + getWidget(mBirthImage, "BirthsignImage"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); + getWidget(mBirthList, "BirthsignList"); + mBirthList->setScrollVisible(true); + mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); - updateBirths(); - updateSpells(); -} - -void BirthDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); -void BirthDialog::open() -{ - WindowModal::open(); - updateBirths(); - updateSpells(); -} + updateBirths(); + updateSpells(); + } - -void BirthDialog::setBirthId(const std::string &birthId) -{ - mCurrentBirthId = birthId; - mBirthList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mBirthList->getItemCount(); - for (size_t i = 0; i < count; ++i) + void BirthDialog::setNextButtonShow(bool shown) { - if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void BirthDialog::open() + { + WindowModal::open(); + updateBirths(); + updateSpells(); + } + + + void BirthDialog::setBirthId(const std::string &birthId) + { + mCurrentBirthId = birthId; + mBirthList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mBirthList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mBirthList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; - } - } - - updateSpells(); -} - -// widget controls - -void BirthDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void BirthDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - const std::string *birthId = mBirthList->getItemDataAt(_index); - if (boost::iequals(mCurrentBirthId, *birthId)) - return; - - mCurrentBirthId = *birthId; - updateSpells(); -} - -// update widget content - -void BirthDialog::updateBirths() -{ - mBirthList->removeAllItems(); - - const MWWorld::Store &signs = - MWBase::Environment::get().getWorld()->getStore().get(); - - // sort by name - std::vector < std::pair > birthSigns; - - MWWorld::Store::iterator it = signs.begin(); - for (; it != signs.end(); ++it) - { - birthSigns.push_back(std::make_pair(it->mId, &(*it))); - } - std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); - - int index = 0; - for (std::vector >::const_iterator it2 = birthSigns.begin(); - it2 != birthSigns.end(); ++it2, ++index) - { - mBirthList->addItem(it2->second->mName, it2->first); - if (mCurrentBirthId.empty()) - { - mBirthList->setIndexSelected(index); - mCurrentBirthId = it2->first; - } - else if (boost::iequals(it2->first, mCurrentBirthId)) - { - mBirthList->setIndexSelected(index); - } - } -} - -void BirthDialog::updateSpells() -{ - for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSpellItems.clear(); - - if (mCurrentBirthId.empty()) - return; - - MWSpellPtr spellWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), 18); - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::BirthSign *birth = - store.get().find(mCurrentBirthId); - - std::string texturePath = std::string("textures\\") + birth->mTexture; - fixTexturePath(texturePath); - mBirthImage->setImageTexture(texturePath); - - std::vector abilities, powers, spells; - - std::vector::const_iterator it = birth->mPowers.mList.begin(); - std::vector::const_iterator end = birth->mPowers.mList.end(); - for (; it != end; ++it) - { - const std::string &spellId = *it; - const ESM::Spell *spell = store.get().search(spellId); - if (!spell) - continue; // Skip spells which cannot be found - ESM::Spell::SpellType type = static_cast(spell->mData.mType); - if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) - continue; // We only want spell, ability and powers. - - if (type == ESM::Spell::ST_Ability) - abilities.push_back(spellId); - else if (type == ESM::Spell::ST_Power) - powers.push_back(spellId); - else if (type == ESM::Spell::ST_Spell) - spells.push_back(spellId); - } - - int i = 0; - - struct { - const std::vector &spells; - const char *label; - } - categories[3] = { - {abilities, "sBirthsignmenu1"}, - {powers, "sPowers"}, - {spells, "sBirthsignmenu2"} - }; - - for (int category = 0; category < 3; ++category) - { - if (!categories[category].spells.empty()) - { - MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); - label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); - mSpellItems.push_back(label); - coord.top += lineHeight; - - std::vector::const_iterator end = categories[category].spells.end(); - for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) + if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) { - const std::string &spellId = *it; - spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); - spellWidget->setSpellId(spellId); + mBirthList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } + } - mSpellItems.push_back(spellWidget); - coord.top += lineHeight; + updateSpells(); + } - MyGUI::IntCoord spellCoord = coord; - spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template? - spellWidget->createEffectWidgets(mSpellItems, mSpellArea, spellCoord, (category == 0) ? MWEffectList::EF_Constant : 0); - coord.top = spellCoord.top; + // widget controls - ++i; + void BirthDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE) + return; + eventDone(this); + } + + void BirthDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) + { + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + const std::string *birthId = mBirthList->getItemDataAt(_index); + if (boost::iequals(mCurrentBirthId, *birthId)) + return; + + mCurrentBirthId = *birthId; + updateSpells(); + } + + // update widget content + + void BirthDialog::updateBirths() + { + mBirthList->removeAllItems(); + + const MWWorld::Store &signs = + MWBase::Environment::get().getWorld()->getStore().get(); + + // sort by name + std::vector < std::pair > birthSigns; + + MWWorld::Store::iterator it = signs.begin(); + for (; it != signs.end(); ++it) + { + birthSigns.push_back(std::make_pair(it->mId, &(*it))); + } + std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); + + int index = 0; + for (std::vector >::const_iterator it2 = birthSigns.begin(); + it2 != birthSigns.end(); ++it2, ++index) + { + mBirthList->addItem(it2->second->mName, it2->first); + if (mCurrentBirthId.empty()) + { + mBirthList->setIndexSelected(index); + mCurrentBirthId = it2->first; + } + else if (boost::iequals(it2->first, mCurrentBirthId)) + { + mBirthList->setIndexSelected(index); } } } + + void BirthDialog::updateSpells() + { + for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSpellItems.clear(); + + if (mCurrentBirthId.empty()) + return; + + Widgets::MWSpellPtr spellWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), 18); + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::BirthSign *birth = + store.get().find(mCurrentBirthId); + + std::string texturePath = std::string("textures\\") + birth->mTexture; + Widgets::fixTexturePath(texturePath); + mBirthImage->setImageTexture(texturePath); + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = birth->mPowers.mList.begin(); + std::vector::const_iterator end = birth->mPowers.mList.end(); + for (; it != end; ++it) + { + const std::string &spellId = *it; + const ESM::Spell *spell = store.get().search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->mData.mType); + if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) + continue; // We only want spell, ability and powers. + + if (type == ESM::Spell::ST_Ability) + abilities.push_back(spellId); + else if (type == ESM::Spell::ST_Power) + powers.push_back(spellId); + else if (type == ESM::Spell::ST_Spell) + spells.push_back(spellId); + } + + int i = 0; + + struct { + const std::vector &spells; + const char *label; + } + categories[3] = { + {abilities, "sBirthsignmenu1"}, + {powers, "sPowers"}, + {spells, "sBirthsignmenu2"} + }; + + for (int category = 0; category < 3; ++category) + { + if (!categories[category].spells.empty()) + { + MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); + label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); + mSpellItems.push_back(label); + coord.top += lineHeight; + + std::vector::const_iterator end = categories[category].spells.end(); + for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) + { + const std::string &spellId = *it; + spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); + spellWidget->setSpellId(spellId); + + mSpellItems.push_back(spellWidget); + coord.top += lineHeight; + + MyGUI::IntCoord spellCoord = coord; + spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template? + spellWidget->createEffectWidgets(mSpellItems, mSpellArea, spellCoord, (category == 0) ? Widgets::MWEffectList::EF_Constant : 0); + coord.top = spellCoord.top; + + ++i; + } + } + } + } + } diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ce74c48593..6d44e9d2c5 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -12,148 +12,151 @@ #include "formatting.hpp" -using namespace MWGui; - -BookWindow::BookWindow () - : WindowBase("openmw_book.layout") - , mTakeButtonShow(true) - , mTakeButtonAllowed(true) +namespace MWGui { - getWidget(mCloseButton, "CloseButton"); - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); - getWidget(mTakeButton, "TakeButton"); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onTakeButtonClicked); - - getWidget(mNextPageButton, "NextPageBTN"); - mNextPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onNextPageButtonClicked); - - getWidget(mPrevPageButton, "PrevPageBTN"); - mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); - - getWidget(mLeftPageNumber, "LeftPageNumber"); - getWidget(mRightPageNumber, "RightPageNumber"); - - getWidget(mLeftPage, "LeftPage"); - getWidget(mRightPage, "RightPage"); - - center(); -} - -void BookWindow::clearPages() -{ - for (std::vector::iterator it=mPages.begin(); - it!=mPages.end(); ++it) + BookWindow::BookWindow () + : WindowBase("openmw_book.layout") + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mPages.clear(); -} + getWidget(mCloseButton, "CloseButton"); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); -void BookWindow::open (MWWorld::Ptr book) -{ - mBook = book; + getWidget(mTakeButton, "TakeButton"); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onTakeButtonClicked); - clearPages(); - mCurrentPage = 0; + getWidget(mNextPageButton, "NextPageBTN"); + mNextPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onNextPageButtonClicked); - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + getWidget(mPrevPageButton, "PrevPageBTN"); + mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); - MWWorld::LiveCellRef *ref = mBook.get(); + getWidget(mLeftPageNumber, "LeftPageNumber"); + getWidget(mRightPageNumber, "RightPageNumber"); - BookTextParser parser; - std::vector results = parser.split(ref->mBase->mText, mLeftPage->getSize().width, mLeftPage->getSize().height); + getWidget(mLeftPage, "LeftPage"); + getWidget(mRightPage, "RightPage"); - int i=0; - for (std::vector::iterator it=results.begin(); - it!=results.end(); ++it) - { - MyGUI::Widget* parent; - if (i%2 == 0) - parent = mLeftPage; - else - parent = mRightPage; - - MyGUI::Widget* pageWidget = parent->createWidgetReal("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast(i)); - parser.parse(*it, pageWidget, mLeftPage->getSize().width); - mPages.push_back(pageWidget); - ++i; + center(); } - updatePages(); - - setTakeButtonShow(true); -} - -void BookWindow::setTakeButtonShow(bool show) -{ - mTakeButtonShow = show; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void BookWindow::setInventoryAllowed(bool allowed) -{ - mTakeButtonAllowed = allowed; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) -{ - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); -} - -void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); - - MWWorld::ActionTake take(mBook); - take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); -} - -void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) -{ - if ((mCurrentPage+1)*2 < mPages.size()) + void BookWindow::clearPages() { - MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); - - ++mCurrentPage; - - updatePages(); - } -} - -void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender) -{ - if (mCurrentPage > 0) - { - MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); - - --mCurrentPage; - - updatePages(); - } -} - -void BookWindow::updatePages() -{ - mLeftPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 1) ); - mRightPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 2) ); - - unsigned int i=0; - for (std::vector::iterator it = mPages.begin(); - it != mPages.end(); ++it) - { - if (mCurrentPage*2 == i || mCurrentPage*2+1 == i) - (*it)->setVisible(true); - else + for (std::vector::iterator it=mPages.begin(); + it!=mPages.end(); ++it) { - (*it)->setVisible(false); + MyGUI::Gui::getInstance().destroyWidget(*it); } - ++i; + mPages.clear(); } + + void BookWindow::open (MWWorld::Ptr book) + { + mBook = book; + + clearPages(); + mCurrentPage = 0; + + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + + MWWorld::LiveCellRef *ref = mBook.get(); + + BookTextParser parser; + std::vector results = parser.split(ref->mBase->mText, mLeftPage->getSize().width, mLeftPage->getSize().height); + + int i=0; + for (std::vector::iterator it=results.begin(); + it!=results.end(); ++it) + { + MyGUI::Widget* parent; + if (i%2 == 0) + parent = mLeftPage; + else + parent = mRightPage; + + MyGUI::Widget* pageWidget = parent->createWidgetReal("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast(i)); + parser.parse(*it, pageWidget, mLeftPage->getSize().width); + mPages.push_back(pageWidget); + ++i; + } + + updatePages(); + + setTakeButtonShow(true); + } + + void BookWindow::setTakeButtonShow(bool show) + { + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void BookWindow::setInventoryAllowed(bool allowed) + { + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) + { + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); + } + + void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); + + MWWorld::ActionTake take(mBook); + take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); + } + + void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) + { + if ((mCurrentPage+1)*2 < mPages.size()) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); + + ++mCurrentPage; + + updatePages(); + } + } + + void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender) + { + if (mCurrentPage > 0) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); + + --mCurrentPage; + + updatePages(); + } + } + + void BookWindow::updatePages() + { + mLeftPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 1) ); + mRightPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 2) ); + + unsigned int i=0; + for (std::vector::iterator it = mPages.begin(); + it != mPages.end(); ++it) + { + if (mCurrentPage*2 == i || mCurrentPage*2+1 == i) + (*it)->setVisible(true); + else + { + (*it)->setVisible(false); + } + ++i; + } + } + } diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 28f6d13ee2..fc8c24484e 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -43,682 +43,685 @@ namespace }; } -using namespace MWGui; - -CharacterCreation::CharacterCreation() - : mNameDialog(0) - , mRaceDialog(0) - , mClassChoiceDialog(0) - , mGenerateClassQuestionDialog(0) - , mGenerateClassResultDialog(0) - , mPickClassDialog(0) - , mCreateClassDialog(0) - , mBirthSignDialog(0) - , mReviewDialog(0) - , mGenerateClassStep(0) +namespace MWGui { - mCreationStage = CSE_NotStarted; -} -void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - if (mReviewDialog) + CharacterCreation::CharacterCreation() + : mNameDialog(0) + , mRaceDialog(0) + , mClassChoiceDialog(0) + , mGenerateClassQuestionDialog(0) + , mGenerateClassResultDialog(0) + , mPickClassDialog(0) + , mCreateClassDialog(0) + , mBirthSignDialog(0) + , mReviewDialog(0) + , mGenerateClassStep(0) { - static const char *ids[] = + mCreationStage = CSE_NotStarted; + } + + void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat& value) + { + if (mReviewDialog) { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) + mReviewDialog->setAttribute(ESM::Attribute::AttributeID(i), value); + } + } + } + + void CharacterCreation::setValue (const std::string& id, const MWMechanics::DynamicStat& value) + { + if (mReviewDialog) + { + if (id == "HBar") + { + mReviewDialog->setHealth (value); + } + else if (id == "MBar") + { + mReviewDialog->setMagicka (value); + } + else if (id == "FBar") + { + mReviewDialog->setFatigue (value); + } + } + } + + void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) + { + if (mReviewDialog) + mReviewDialog->setSkillValue(parSkill, value); + } + + void CharacterCreation::configureSkills (const SkillList& major, const SkillList& minor) + { + if (mReviewDialog) + mReviewDialog->configureSkills(major, minor); + } + + void CharacterCreation::spawnDialog(const char id) + { + switch (id) + { + case GM_Name: + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); + mNameDialog->setTextInput(mPlayerName); + mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); + mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); + mNameDialog->setVisible(true); + break; + + case GM_Race: + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + mRaceDialog = new RaceDialog(); + mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); + mRaceDialog->setRaceId(mPlayerRaceId); + mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); + mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); + mRaceDialog->setVisible(true); + if (mCreationStage < CSE_NameChosen) + mCreationStage = CSE_NameChosen; + break; + + case GM_Class: + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + mClassChoiceDialog = new ClassChoiceDialog(); + mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); + mClassChoiceDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + + case GM_ClassPick: + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + mPickClassDialog = new PickClassDialog(); + mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mPickClassDialog->setClassId(mPlayerClass.mName); + mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); + mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); + mPickClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + + case GM_Birth: + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + mBirthSignDialog = new BirthDialog(); + mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); + mBirthSignDialog->setBirthId(mPlayerBirthSignId); + mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); + mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); + mBirthSignDialog->setVisible(true); + if (mCreationStage < CSE_ClassChosen) + mCreationStage = CSE_ClassChosen; + break; + + case GM_ClassCreate: + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); + mCreateClassDialog = 0; + mCreateClassDialog = new CreateClassDialog(); + mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); + mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); + mCreateClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_ClassGenerate: + mGenerateClassStep = 0; + mGenerateClass = ""; + mGenerateClassSpecializations[0] = 0; + mGenerateClassSpecializations[1] = 0; + mGenerateClassSpecializations[2] = 0; + showClassQuestionDialog(); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_Review: + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mReviewDialog = new ReviewDialog(); + mReviewDialog->setPlayerName(mPlayerName); + mReviewDialog->setRace(mPlayerRaceId); + mReviewDialog->setClass(mPlayerClass); + mReviewDialog->setBirthSign(mPlayerBirthSignId); + + mReviewDialog->setHealth(mPlayerHealth); + mReviewDialog->setMagicka(mPlayerMagicka); + mReviewDialog->setFatigue(mPlayerFatigue); + + { + std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); + for (std::map >::iterator it = attributes.begin(); + it != attributes.end(); ++it) + { + mReviewDialog->setAttribute(static_cast (it->first), it->second); + } + } + + { + std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); + for (std::map >::iterator it = skills.begin(); + it != skills.end(); ++it) + { + mReviewDialog->setSkillValue(static_cast (it->first), it->second); + } + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); + } + + mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); + mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); + mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); + mReviewDialog->setVisible(true); + if (mCreationStage < CSE_BirthSignChosen) + mCreationStage = CSE_BirthSignChosen; + break; + } + } + + void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) + { + mPlayerHealth = value; + } + + void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat& value) + { + mPlayerMagicka = value; + } + + void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& value) + { + mPlayerFatigue = value; + } + + void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + + void CharacterCreation::onReviewDialogBack() + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + + void CharacterCreation::onReviewActivateDialog(int parDialog) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mCreationStage = CSE_ReviewNext; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + switch(parDialog) + { + case ReviewDialog::NAME_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); + break; + case ReviewDialog::RACE_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + break; + case ReviewDialog::CLASS_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + break; + case ReviewDialog::BIRTHSIGN_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); }; - - for (int i=0; ids[i]; ++i) - { - if (ids[i]==id) - mReviewDialog->setAttribute(ESM::Attribute::AttributeID(i), value); - } } -} -void CharacterCreation::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - if (mReviewDialog) + void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) { - if (id == "HBar") + if (mPickClassDialog) { - mReviewDialog->setHealth (value); - } - else if (id == "MBar") - { - mReviewDialog->setMagicka (value); - } - else if (id == "FBar") - { - mReviewDialog->setFatigue (value); - } - } -} + const std::string &classId = mPickClassDialog->getClassId(); + if (!classId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); -void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) -{ - if (mReviewDialog) - mReviewDialog->setSkillValue(parSkill, value); -} - -void CharacterCreation::configureSkills (const SkillList& major, const SkillList& minor) -{ - if (mReviewDialog) - mReviewDialog->configureSkills(major, minor); -} - -void CharacterCreation::spawnDialog(const char id) -{ - switch (id) - { - case GM_Name: - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - mNameDialog = new TextInputDialog(); - mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); - mNameDialog->setTextInput(mPlayerName); - mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); - mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); - mNameDialog->setVisible(true); - break; - - case GM_Race: - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - mRaceDialog = new RaceDialog(); - mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); - mRaceDialog->setRaceId(mPlayerRaceId); - mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); - mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); - mRaceDialog->setVisible(true); - if (mCreationStage < CSE_NameChosen) - mCreationStage = CSE_NameChosen; - break; - - case GM_Class: - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(); - mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); - mClassChoiceDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - - case GM_ClassPick: + const ESM::Class *klass = + MWBase::Environment::get().getWorld()->getStore().get().find(classId); + if (klass) + { + mPlayerClass = *klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + } MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(); - mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mPickClassDialog->setClassId(mPlayerClass.mName); - mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); - mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); - mPickClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + } - case GM_Birth: + //TODO This bit gets repeated a few times; wrap it in a function + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + else + { + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onPickClassDialogBack() + { + if (mPickClassDialog) + { + const std::string classId = mPickClassDialog->getClassId(); + if (!classId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onClassChoice(int _index) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + switch(_index) + { + case ClassChoiceDialog::Class_Generate: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); + break; + case ClassChoiceDialog::Class_Pick: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); + break; + case ClassChoiceDialog::Class_Create: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); + break; + case ClassChoiceDialog::Class_Back: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + break; + + }; + } + + void CharacterCreation::onNameDialogDone(WindowBase* parWindow) + { + if (mNameDialog) + { + mPlayerName = mNameDialog->getTextInput(); + MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); + MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + } + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_NameChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + } + else + { + mCreationStage = CSE_NameChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onRaceDialogBack() + { + if (mRaceDialog) + { + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); + } + + void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) + { + if (mRaceDialog) + { + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); + + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + } + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_RaceChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + else + { + mCreationStage = CSE_RaceChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + { + if (mBirthSignDialog) + { + mPlayerBirthSignId = mBirthSignDialog->getBirthId(); + if (!mPlayerBirthSignId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(); - mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); - mBirthSignDialog->setBirthId(mPlayerBirthSignId); - mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); - mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); - mBirthSignDialog->setVisible(true); - if (mCreationStage < CSE_ClassChosen) - mCreationStage = CSE_ClassChosen; - break; + } + + if (mCreationStage >= CSE_BirthSignChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else + { + mCreationStage = CSE_BirthSignChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onBirthSignDialogBack() + { + if (mBirthSignDialog) + { + MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + { + if (mCreateClassDialog) + { + ESM::Class klass; + klass.mName = mCreateClassDialog->getName(); + klass.mDescription = mCreateClassDialog->getDescription(); + klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); + klass.mData.mIsPlayable = 0x1; + + std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); + assert(attributes.size() == 2); + klass.mData.mAttribute[0] = attributes[0]; + klass.mData.mAttribute[1] = attributes[1]; + + std::vector majorSkills = mCreateClassDialog->getMajorSkills(); + std::vector minorSkills = mCreateClassDialog->getMinorSkills(); + assert(majorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); + assert(minorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); + for (size_t i = 0; i < sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0]); ++i) + { + klass.mData.mSkills[i][1] = majorSkills[i]; + klass.mData.mSkills[i][0] = minorSkills[i]; + } + + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); + mPlayerClass = klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - case GM_ClassCreate: MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mCreateClassDialog = new CreateClassDialog(); - mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); - mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); - mCreateClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_ClassGenerate: - mGenerateClassStep = 0; - mGenerateClass = ""; - mGenerateClassSpecializations[0] = 0; - mGenerateClassSpecializations[1] = 0; - mGenerateClassSpecializations[2] = 0; - showClassQuestionDialog(); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_Review: - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mReviewDialog = new ReviewDialog(); - mReviewDialog->setPlayerName(mPlayerName); - mReviewDialog->setRace(mPlayerRaceId); - mReviewDialog->setClass(mPlayerClass); - mReviewDialog->setBirthSign(mPlayerBirthSignId); + } - mReviewDialog->setHealth(mPlayerHealth); - mReviewDialog->setMagicka(mPlayerMagicka); - mReviewDialog->setFatigue(mPlayerFatigue); - - { - std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map >::iterator it = attributes.begin(); - it != attributes.end(); ++it) - { - mReviewDialog->setAttribute(static_cast (it->first), it->second); - } - } - - { - std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map >::iterator it = skills.begin(); - it != skills.end(); ++it) - { - mReviewDialog->setSkillValue(static_cast (it->first), it->second); - } - mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); - } - - mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); - mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); - mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); - mReviewDialog->setVisible(true); - if (mCreationStage < CSE_BirthSignChosen) - mCreationStage = CSE_BirthSignChosen; - break; - } -} - -void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) -{ - mPlayerHealth = value; -} - -void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat& value) -{ - mPlayerMagicka = value; -} - -void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& value) -{ - mPlayerFatigue = value; -} - -void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); -} - -void CharacterCreation::onReviewDialogBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); -} - -void CharacterCreation::onReviewActivateDialog(int parDialog) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mCreationStage = CSE_ReviewNext; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - - switch(parDialog) - { - case ReviewDialog::NAME_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); - break; - case ReviewDialog::RACE_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - break; - case ReviewDialog::CLASS_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - break; - case ReviewDialog::BIRTHSIGN_DIALOG: + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - }; -} - -void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) -{ - if (mPickClassDialog) - { - const std::string &classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - - const ESM::Class *klass = - MWBase::Environment::get().getWorld()->getStore().get().find(classId); - if (klass) + } + else { - mPlayerClass = *klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); } - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; } - //TODO This bit gets repeated a few times; wrap it in a function - if (mCreationStage == CSE_ReviewNext) + void CharacterCreation::onCreateClassDialogBack() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onPickClassDialogBack() -{ - if (mPickClassDialog) - { - const std::string classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onClassChoice(int _index) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - - switch(_index) - { - case ClassChoiceDialog::Class_Generate: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); - break; - case ClassChoiceDialog::Class_Pick: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); - break; - case ClassChoiceDialog::Class_Create: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); - break; - case ClassChoiceDialog::Class_Back: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - break; - - }; -} - -void CharacterCreation::onNameDialogDone(WindowBase* parWindow) -{ - if (mNameDialog) - { - mPlayerName = mNameDialog->getTextInput(); - MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); - MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - } - - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_NameChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - } - else - { - mCreationStage = CSE_NameChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onRaceDialogBack() -{ - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); -} - -void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) -{ - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); - - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_RaceChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - else - { - mCreationStage = CSE_RaceChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) -{ - if (mBirthSignDialog) - { - mPlayerBirthSignId = mBirthSignDialog->getBirthId(); - if (!mPlayerBirthSignId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } - - if (mCreationStage >= CSE_BirthSignChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else - { - mCreationStage = CSE_BirthSignChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onBirthSignDialogBack() -{ - if (mBirthSignDialog) - { - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) -{ - if (mCreateClassDialog) - { - ESM::Class klass; - klass.mName = mCreateClassDialog->getName(); - klass.mDescription = mCreateClassDialog->getDescription(); - klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); - klass.mData.mIsPlayable = 0x1; - - std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); - assert(attributes.size() == 2); - klass.mData.mAttribute[0] = attributes[0]; - klass.mData.mAttribute[1] = attributes[1]; - - std::vector majorSkills = mCreateClassDialog->getMajorSkills(); - std::vector minorSkills = mCreateClassDialog->getMinorSkills(); - assert(majorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); - assert(minorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); - for (size_t i = 0; i < sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0]); ++i) - { - klass.mData.mSkills[i][1] = majorSkills[i]; - klass.mData.mSkills[i][0] = minorSkills[i]; - } - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); - mPlayerClass = klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - } - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onCreateClassDialogBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); - mCreateClassDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onClassQuestionChosen(int _index) -{ - MWBase::Environment::get().getSoundManager()->stopSay(); - - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); - mGenerateClassQuestionDialog = 0; - - if (_index < 0 || _index >= 3) - { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - return; } - ESM::Class::Specialization specialization = mSpecializations[_index]; - if (specialization == ESM::Class::Stealth) - ++mGenerateClassSpecializations[0]; - else if (specialization == ESM::Class::Combat) - ++mGenerateClassSpecializations[1]; - else if (specialization == ESM::Class::Magic) - ++mGenerateClassSpecializations[2]; - ++mGenerateClassStep; - showClassQuestionDialog(); -} - -void CharacterCreation::showClassQuestionDialog() -{ - if (mGenerateClassStep == 10) + void CharacterCreation::onClassQuestionChosen(int _index) { - static boost::array classes = { { - {"Acrobat", {6, 2, 2}}, - {"Agent", {6, 1, 3}}, - {"Archer", {3, 5, 2}}, - {"Archer", {5, 5, 0}}, - {"Assassin", {6, 3, 1}}, - {"Barbarian", {3, 6, 1}}, - {"Bard", {3, 3, 3}}, - {"Battlemage", {1, 3, 6}}, - {"Crusader", {1, 6, 3}}, - {"Healer", {3, 1, 6}}, - {"Knight", {2, 6, 2}}, - {"Monk", {5, 3, 2}}, - {"Nightblade", {4, 2, 4}}, - {"Pilgrim", {5, 2, 3}}, - {"Rogue", {3, 4, 3}}, - {"Rogue", {4, 4, 2}}, - {"Rogue", {5, 4, 1}}, - {"Scout", {2, 5, 3}}, - {"Sorcerer", {2, 2, 6}}, - {"Spellsword", {2, 4, 4}}, - {"Spellsword", {5, 1, 4}}, - {"Witchhunter", {2, 3, 5}}, - {"Witchhunter", {5, 0, 5}} - } }; + MWBase::Environment::get().getSoundManager()->stopSay(); - int match = -1; - for (unsigned i = 0; i < classes.size(); ++i) + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); + mGenerateClassQuestionDialog = 0; + + if (_index < 0 || _index >= 3) { - if (mGenerateClassSpecializations[0] == classes[i].points[0] && - mGenerateClassSpecializations[1] == classes[i].points[1] && - mGenerateClassSpecializations[2] == classes[i].points[2]) - { - match = i; - mGenerateClass = classes[i].id; - break; - } + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + return; } - if (match == -1) + ESM::Class::Specialization specialization = mSpecializations[_index]; + if (specialization == ESM::Class::Stealth) + ++mGenerateClassSpecializations[0]; + else if (specialization == ESM::Class::Combat) + ++mGenerateClassSpecializations[1]; + else if (specialization == ESM::Class::Magic) + ++mGenerateClassSpecializations[2]; + ++mGenerateClassStep; + showClassQuestionDialog(); + } + + void CharacterCreation::showClassQuestionDialog() + { + if (mGenerateClassStep == 10) { - if (mGenerateClassSpecializations[0] >= 7) - mGenerateClass = "Thief"; - else if (mGenerateClassSpecializations[1] >= 7) - mGenerateClass = "Warrior"; - else if (mGenerateClassSpecializations[2] >= 7) - mGenerateClass = "Mage"; - else + static boost::array classes = { { + {"Acrobat", {6, 2, 2}}, + {"Agent", {6, 1, 3}}, + {"Archer", {3, 5, 2}}, + {"Archer", {5, 5, 0}}, + {"Assassin", {6, 3, 1}}, + {"Barbarian", {3, 6, 1}}, + {"Bard", {3, 3, 3}}, + {"Battlemage", {1, 3, 6}}, + {"Crusader", {1, 6, 3}}, + {"Healer", {3, 1, 6}}, + {"Knight", {2, 6, 2}}, + {"Monk", {5, 3, 2}}, + {"Nightblade", {4, 2, 4}}, + {"Pilgrim", {5, 2, 3}}, + {"Rogue", {3, 4, 3}}, + {"Rogue", {4, 4, 2}}, + {"Rogue", {5, 4, 1}}, + {"Scout", {2, 5, 3}}, + {"Sorcerer", {2, 2, 6}}, + {"Spellsword", {2, 4, 4}}, + {"Spellsword", {5, 1, 4}}, + {"Witchhunter", {2, 3, 5}}, + {"Witchhunter", {5, 0, 5}} + } }; + + int match = -1; + for (unsigned i = 0; i < classes.size(); ++i) { - std::cerr << "Failed to deduce class from chosen answers in generate class dialog" << std::endl; - mGenerateClass = "Thief"; + if (mGenerateClassSpecializations[0] == classes[i].points[0] && + mGenerateClassSpecializations[1] == classes[i].points[1] && + mGenerateClassSpecializations[2] == classes[i].points[2]) + { + match = i; + mGenerateClass = classes[i].id; + break; + } } + + if (match == -1) + { + if (mGenerateClassSpecializations[0] >= 7) + mGenerateClass = "Thief"; + else if (mGenerateClassSpecializations[1] >= 7) + mGenerateClass = "Warrior"; + else if (mGenerateClassSpecializations[2] >= 7) + mGenerateClass = "Mage"; + else + { + std::cerr << "Failed to deduce class from chosen answers in generate class dialog" << std::endl; + mGenerateClass = "Thief"; + } + } + + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + + mGenerateClassResultDialog = new GenerateClassResultDialog(); + mGenerateClassResultDialog->setClassId(mGenerateClass); + mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); + mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); + mGenerateClassResultDialog->setVisible(true); + return; } + if (mGenerateClassStep > 10) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + return; + } + + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); + mGenerateClassQuestionDialog = 0; + + mGenerateClassQuestionDialog = new InfoBoxDialog(); + + InfoBoxDialog::ButtonList buttons; + mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[0]); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[1]); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[2]); + mGenerateClassQuestionDialog->setButtons(buttons); + mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); + mGenerateClassQuestionDialog->setVisible(true); + + MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); + } + + void CharacterCreation::onGenerateClassBack() + { MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; - mGenerateClassResultDialog = new GenerateClassResultDialog(); - mGenerateClassResultDialog->setClassId(mGenerateClass); - mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); - mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); - mGenerateClassResultDialog->setVisible(true); - return; - } + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - if (mGenerateClassStep > 10) - { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - return; } - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); - mGenerateClassQuestionDialog = 0; - - mGenerateClassQuestionDialog = new InfoBoxDialog(); - - InfoBoxDialog::ButtonList buttons; - mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[0]); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[1]); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[2]); - mGenerateClassQuestionDialog->setButtons(buttons); - mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); - mGenerateClassQuestionDialog->setVisible(true); - - MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); -} - -void CharacterCreation::onGenerateClassBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - const ESM::Class *klass = - MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); - - mPlayerClass = *klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); - - if (mCreationStage == CSE_ReviewNext) + void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); + + const ESM::Class *klass = + MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); + + mPlayerClass = *klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + else + { + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + CharacterCreation::~CharacterCreation() + { + delete mNameDialog; + delete mRaceDialog; + delete mClassChoiceDialog; + delete mGenerateClassQuestionDialog; + delete mGenerateClassResultDialog; + delete mPickClassDialog; + delete mCreateClassDialog; + delete mBirthSignDialog; + delete mReviewDialog; + } -CharacterCreation::~CharacterCreation() -{ - delete mNameDialog; - delete mRaceDialog; - delete mClassChoiceDialog; - delete mGenerateClassQuestionDialog; - delete mGenerateClassResultDialog; - delete mPickClassDialog; - delete mCreateClassDialog; - delete mBirthSignDialog; - delete mReviewDialog; } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e4d32c933b..ab81038689 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -11,870 +11,873 @@ #undef min #undef max -using namespace MWGui; - -/* GenerateClassResultDialog */ - -GenerateClassResultDialog::GenerateClassResultDialog() - : WindowModal("openmw_chargen_generate_class_result.layout") +namespace MWGui { - // Centre dialog - center(); - setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); + /* GenerateClassResultDialog */ - getWidget(mClassImage, "ClassImage"); - getWidget(mClassName, "ClassName"); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); -} - -std::string GenerateClassResultDialog::getClassId() const -{ - return mClassName->getCaption(); -} - -void GenerateClassResultDialog::setClassId(const std::string &classId) -{ - mCurrentClassId = classId; - mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); - mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().get().find(mCurrentClassId)->mName); -} - -// widget controls - -void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); -} - -void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -/* PickClassDialog */ - -PickClassDialog::PickClassDialog() - : WindowModal("openmw_chargen_class.layout") -{ - // Centre dialog - center(); - - getWidget(mSpecializationName, "SpecializationName"); - - getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); - getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); - - for(int i = 0; i < 5; i++) + GenerateClassResultDialog::GenerateClassResultDialog() + : WindowModal("openmw_chargen_generate_class_result.layout") { - char theIndex = '0'+i; - getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); - getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - } + // Centre dialog + center(); - getWidget(mClassList, "ClassList"); - mClassList->setScrollVisible(true); - mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); - getWidget(mClassImage, "ClassImage"); + getWidget(mClassImage, "ClassImage"); + getWidget(mClassName, "ClassName"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); - - updateClasses(); - updateStats(); -} - -void PickClassDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); + } -void PickClassDialog::open() -{ - WindowModal::open (); - updateClasses(); - updateStats(); -} - - -void PickClassDialog::setClassId(const std::string &classId) -{ - mCurrentClassId = classId; - mClassList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mClassList->getItemCount(); - for (size_t i = 0; i < count; ++i) + std::string GenerateClassResultDialog::getClassId() const { - if (boost::iequals(*mClassList->getItemDataAt(i), classId)) + return mClassName->getCaption(); + } + + void GenerateClassResultDialog::setClassId(const std::string &classId) + { + mCurrentClassId = classId; + mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); + mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().get().find(mCurrentClassId)->mName); + } + + // widget controls + + void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); + } + + void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + /* PickClassDialog */ + + PickClassDialog::PickClassDialog() + : WindowModal("openmw_chargen_class.layout") + { + // Centre dialog + center(); + + getWidget(mSpecializationName, "SpecializationName"); + + getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); + getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); + + for(int i = 0; i < 5; i++) { - mClassList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; + char theIndex = '0'+i; + getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); + getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); } + + getWidget(mClassList, "ClassList"); + mClassList->setScrollVisible(true); + mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + + getWidget(mClassImage, "ClassImage"); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); + + updateClasses(); + updateStats(); } - updateStats(); -} - -// widget controls - -void PickClassDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void PickClassDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - const std::string *classId = mClassList->getItemDataAt(_index); - if (boost::iequals(mCurrentClassId, *classId)) - return; - - mCurrentClassId = *classId; - updateStats(); -} - -// update widget content - -void PickClassDialog::updateClasses() -{ - mClassList->removeAllItems(); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - - int index = 0; - MWWorld::Store::iterator it = store.get().begin(); - for (; it != store.get().end(); ++it) + void PickClassDialog::setNextButtonShow(bool shown) { - bool playable = (it->mData.mIsPlayable != 0); - if (!playable) // Only display playable classes - continue; + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); - const std::string &id = it->mId; - mClassList->addItem(it->mName, id); - if (mCurrentClassId.empty()) + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void PickClassDialog::open() + { + WindowModal::open (); + updateClasses(); + updateStats(); + } + + + void PickClassDialog::setClassId(const std::string &classId) + { + mCurrentClassId = classId; + mClassList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mClassList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mCurrentClassId = id; - mClassList->setIndexSelected(index); + if (boost::iequals(*mClassList->getItemDataAt(i), classId)) + { + mClassList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } } - else if (boost::iequals(id, mCurrentClassId)) - { - mClassList->setIndexSelected(index); - } - ++index; - } -} -void PickClassDialog::updateStats() -{ - if (mCurrentClassId.empty()) - return; - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Class *klass = store.get().search(mCurrentClassId); - if (!klass) - return; - - ESM::Class::Specialization specialization = static_cast(klass->mData.mSpecialization); - - static const char *specIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" - }; - std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); - mSpecializationName->setCaption(specName); - ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); - - mFavoriteAttribute[0]->setAttributeId(klass->mData.mAttribute[0]); - mFavoriteAttribute[1]->setAttributeId(klass->mData.mAttribute[1]); - ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); - ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); - - for (int i = 0; i < 5; ++i) - { - mMinorSkill[i]->setSkillNumber(klass->mData.mSkills[i][0]); - mMajorSkill[i]->setSkillNumber(klass->mData.mSkills[i][1]); - ToolTips::createSkillToolTip(mMinorSkill[i], klass->mData.mSkills[i][0]); - ToolTips::createSkillToolTip(mMajorSkill[i], klass->mData.mSkills[i][1]); + updateStats(); } - mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); -} + // widget controls -/* InfoBoxDialog */ - -void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) -{ - MyGUI::IntCoord inner = widget->getTextRegion(); - MyGUI::IntCoord outer = widget->getCoord(); - MyGUI::IntSize size = widget->getTextSize(); - size.width += outer.width - inner.width; - size.height += outer.height - inner.height; - widget->setSize(size); -} - -void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) -{ - size_t count = widget->getChildCount(); - int pos = 0; - pos += margin; - int width = 0; - for (unsigned i = 0; i < count; ++i) + void PickClassDialog::onOkClicked(MyGUI::Widget* _sender) { - MyGUI::Widget* child = widget->getChildAt(i); - if (!child->getVisible()) - continue; - - child->setPosition(child->getLeft(), pos); - width = std::max(width, child->getWidth()); - pos += child->getHeight() + margin; - } - width += margin*2; - widget->setSize(width, pos); -} - -InfoBoxDialog::InfoBoxDialog() - : WindowModal("openmw_infobox.layout") - , mCurrentButton(-1) -{ - getWidget(mTextBox, "TextBox"); - getWidget(mText, "Text"); - mText->getSubWidgetText()->setWordWrap(true); - getWidget(mButtonBar, "ButtonBar"); - - center(); -} - -void InfoBoxDialog::setText(const std::string &str) -{ - mText->setCaption(str); - mTextBox->setVisible(!str.empty()); - fitToText(mText); -} - -std::string InfoBoxDialog::getText() const -{ - return mText->getCaption(); -} - -void InfoBoxDialog::setButtons(ButtonList &buttons) -{ - for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - this->mButtons.clear(); - mCurrentButton = -1; - - // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget - MyGUI::Button* button; - MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); - ButtonList::const_iterator end = buttons.end(); - for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) - { - const std::string &text = *it; - button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); - button->getSubWidgetText()->setWordWrap(true); - button->setCaption(text); - fitToText(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); - coord.top += button->getHeight(); - this->mButtons.push_back(button); - } -} - -void InfoBoxDialog::open() -{ - WindowModal::open(); - // Fix layout - layoutVertically(mTextBox, 4); - layoutVertically(mButtonBar, 6); - layoutVertically(mMainWidget, 4 + 6); - - center(); -} - -int InfoBoxDialog::getChosenButton() const -{ - return mCurrentButton; -} - -void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) -{ - std::vector::const_iterator end = mButtons.end(); - int i = 0; - for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) - { - if (*it == _sender) - { - mCurrentButton = i; - eventButtonSelected(i); + if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE) return; - } - ++i; - } -} - -/* ClassChoiceDialog */ - -ClassChoiceDialog::ClassChoiceDialog() - : InfoBoxDialog() -{ - setText(""); - ButtonList buttons; - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); - setButtons(buttons); -} - -/* CreateClassDialog */ - -CreateClassDialog::CreateClassDialog() - : WindowModal("openmw_chargen_create_class.layout") - , mSpecDialog(NULL) - , mAttribDialog(NULL) - , mSkillDialog(NULL) - , mDescDialog(NULL) -{ - // Centre dialog - center(); - - setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); - getWidget(mSpecializationName, "SpecializationName"); - mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); - - setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); - getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); - getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); - mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - - setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); - setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); - for(int i = 0; i < 5; i++) - { - char theIndex = '0'+i; - getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); - getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - mSkills.push_back(mMajorSkill[i]); - mSkills.push_back(mMinorSkill[i]); + eventDone(this); } - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + void PickClassDialog::onBackClicked(MyGUI::Widget* _sender) { - (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + eventBack(); } - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); - getWidget(mEditName, "EditName"); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); - - MyGUI::Button* descriptionButton; - getWidget(descriptionButton, "DescriptionButton"); - descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); - - // Set default skills, attributes - - mFavoriteAttribute0->setAttributeId(ESM::Attribute::Strength); - mFavoriteAttribute1->setAttributeId(ESM::Attribute::Agility); - - mMajorSkill[0]->setSkillId(ESM::Skill::Block); - mMajorSkill[1]->setSkillId(ESM::Skill::Armorer); - mMajorSkill[2]->setSkillId(ESM::Skill::MediumArmor); - mMajorSkill[3]->setSkillId(ESM::Skill::HeavyArmor); - mMajorSkill[4]->setSkillId(ESM::Skill::BluntWeapon); - - mMinorSkill[0]->setSkillId(ESM::Skill::LongBlade); - mMinorSkill[1]->setSkillId(ESM::Skill::Axe); - mMinorSkill[2]->setSkillId(ESM::Skill::Spear); - mMinorSkill[3]->setSkillId(ESM::Skill::Athletics); - mMinorSkill[4]->setSkillId(ESM::Skill::Enchant); - - setSpecialization(0); - update(); -} - -CreateClassDialog::~CreateClassDialog() -{ - delete mSpecDialog; - delete mAttribDialog; - delete mSkillDialog; - delete mDescDialog; -} - -void CreateClassDialog::update() -{ - for (int i = 0; i < 5; ++i) + void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) { - ToolTips::createSkillToolTip(mMajorSkill[i], mMajorSkill[i]->getSkillId()); - ToolTips::createSkillToolTip(mMinorSkill[i], mMinorSkill[i]->getSkillId()); + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + const std::string *classId = mClassList->getItemDataAt(_index); + if (boost::iequals(mCurrentClassId, *classId)) + return; + + mCurrentClassId = *classId; + updateStats(); } - ToolTips::createAttributeToolTip(mFavoriteAttribute0, mFavoriteAttribute0->getAttributeId()); - ToolTips::createAttributeToolTip(mFavoriteAttribute1, mFavoriteAttribute1->getAttributeId()); -} + // update widget content -std::string CreateClassDialog::getName() const -{ - return mEditName->getOnlyText(); -} - -std::string CreateClassDialog::getDescription() const -{ - return mDescription; -} - -ESM::Class::Specialization CreateClassDialog::getSpecializationId() const -{ - return mSpecializationId; -} - -std::vector CreateClassDialog::getFavoriteAttributes() const -{ - std::vector v; - v.push_back(mFavoriteAttribute0->getAttributeId()); - v.push_back(mFavoriteAttribute1->getAttributeId()); - return v; -} - -std::vector CreateClassDialog::getMajorSkills() const -{ - std::vector v; - for(int i = 0; i < 5; i++) + void PickClassDialog::updateClasses() { - v.push_back(mMajorSkill[i]->getSkillId()); - } - return v; -} + mClassList->removeAllItems(); -std::vector CreateClassDialog::getMinorSkills() const -{ - std::vector v; - for(int i=0; i < 5; i++) - { - v.push_back(mMinorSkill[i]->getSkillId()); - } - return v; -} + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); -void CreateClassDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -// widget controls - -void CreateClassDialog::onDialogCancel() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); - mSpecDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); - mAttribDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); - mSkillDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); - mDescDialog = 0; -} - -void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) -{ - delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(); - mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); - mSpecDialog->setVisible(true); -} - -void CreateClassDialog::onSpecializationSelected() -{ - mSpecializationId = mSpecDialog->getSpecializationId(); - setSpecialization(mSpecializationId); - - MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); - mSpecDialog = 0; -} - -void CreateClassDialog::setSpecialization(int id) -{ - mSpecializationId = (ESM::Class::Specialization) id; - static const char *specIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" - }; - std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); - mSpecializationName->setCaption(specName); - ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); -} - -void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) -{ - delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(); - mAffectedAttribute = _sender; - mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); - mAttribDialog->setVisible(true); -} - -void CreateClassDialog::onAttributeSelected() -{ - ESM::Attribute::AttributeID id = mAttribDialog->getAttributeId(); - if (mAffectedAttribute == mFavoriteAttribute0) - { - if (mFavoriteAttribute1->getAttributeId() == id) - mFavoriteAttribute1->setAttributeId(mFavoriteAttribute0->getAttributeId()); - } - else if (mAffectedAttribute == mFavoriteAttribute1) - { - if (mFavoriteAttribute0->getAttributeId() == id) - mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); - } - mAffectedAttribute->setAttributeId(id); - MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); - mAttribDialog = 0; - - update(); -} - -void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) -{ - delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(); - mAffectedSkill = _sender; - mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); - mSkillDialog->setVisible(true); -} - -void CreateClassDialog::onSkillSelected() -{ - ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); - - // Avoid duplicate skills by swapping any skill field that matches the selected one - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) - { - if (*it == mAffectedSkill) - continue; - if ((*it)->getSkillId() == id) + int index = 0; + MWWorld::Store::iterator it = store.get().begin(); + for (; it != store.get().end(); ++it) { - (*it)->setSkillId(mAffectedSkill->getSkillId()); - break; + bool playable = (it->mData.mIsPlayable != 0); + if (!playable) // Only display playable classes + continue; + + const std::string &id = it->mId; + mClassList->addItem(it->mName, id); + if (mCurrentClassId.empty()) + { + mCurrentClassId = id; + mClassList->setIndexSelected(index); + } + else if (boost::iequals(id, mCurrentClassId)) + { + mClassList->setIndexSelected(index); + } + ++index; } } - mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); - mSkillDialog = 0; - update(); -} + void PickClassDialog::updateStats() + { + if (mCurrentClassId.empty()) + return; + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Class *klass = store.get().search(mCurrentClassId); + if (!klass) + return; -void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) -{ - mDescDialog = new DescriptionDialog(); - mDescDialog->setTextInput(mDescription); - mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); - mDescDialog->setVisible(true); -} + ESM::Class::Specialization specialization = static_cast(klass->mData.mSpecialization); -void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) -{ - mDescription = mDescDialog->getTextInput(); - MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); - mDescDialog = 0; -} + static const char *specIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); + mSpecializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); -void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(getName().size() <= 0) - return; - eventDone(this); -} + mFavoriteAttribute[0]->setAttributeId(klass->mData.mAttribute[0]); + mFavoriteAttribute[1]->setAttributeId(klass->mData.mAttribute[1]); + ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); -void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} + for (int i = 0; i < 5; ++i) + { + mMinorSkill[i]->setSkillNumber(klass->mData.mSkills[i][0]); + mMajorSkill[i]->setSkillNumber(klass->mData.mSkills[i][1]); + ToolTips::createSkillToolTip(mMinorSkill[i], klass->mData.mSkills[i][0]); + ToolTips::createSkillToolTip(mMajorSkill[i], klass->mData.mSkills[i][1]); + } -/* SelectSpecializationDialog */ + mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); + } -SelectSpecializationDialog::SelectSpecializationDialog() - : WindowModal("openmw_chargen_select_specialization.layout") -{ - // Centre dialog - center(); + /* InfoBoxDialog */ - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); + void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) + { + MyGUI::IntCoord inner = widget->getTextRegion(); + MyGUI::IntCoord outer = widget->getCoord(); + MyGUI::IntSize size = widget->getTextSize(); + size.width += outer.width - inner.width; + size.height += outer.height - inner.height; + widget->setSize(size); + } - getWidget(mSpecialization0, "Specialization0"); - getWidget(mSpecialization1, "Specialization1"); - getWidget(mSpecialization2, "Specialization2"); - std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); - std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); - std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) + { + size_t count = widget->getChildCount(); + int pos = 0; + pos += margin; + int width = 0; + for (unsigned i = 0; i < count; ++i) + { + MyGUI::Widget* child = widget->getChildAt(i); + if (!child->getVisible()) + continue; - mSpecialization0->setCaption(combat); - mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecialization1->setCaption(magic); - mSpecialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecialization2->setCaption(stealth); - mSpecialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecializationId = ESM::Class::Combat; + child->setPosition(child->getLeft(), pos); + width = std::max(width, child->getWidth()); + pos += child->getHeight() + margin; + } + width += margin*2; + widget->setSize(width, pos); + } - ToolTips::createSpecializationToolTip(mSpecialization0, combat, ESM::Class::Combat); - ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); - ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); + InfoBoxDialog::InfoBoxDialog() + : WindowModal("openmw_infobox.layout") + , mCurrentButton(-1) + { + getWidget(mTextBox, "TextBox"); + getWidget(mText, "Text"); + mText->getSubWidgetText()->setWordWrap(true); + getWidget(mButtonBar, "ButtonBar"); - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); -} + center(); + } -SelectSpecializationDialog::~SelectSpecializationDialog() -{ -} + void InfoBoxDialog::setText(const std::string &str) + { + mText->setCaption(str); + mTextBox->setVisible(!str.empty()); + fitToText(mText); + } -// widget controls + std::string InfoBoxDialog::getText() const + { + return mText->getCaption(); + } -void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender) -{ - if (_sender == mSpecialization0) + void InfoBoxDialog::setButtons(ButtonList &buttons) + { + for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + this->mButtons.clear(); + mCurrentButton = -1; + + // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget + MyGUI::Button* button; + MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); + ButtonList::const_iterator end = buttons.end(); + for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) + { + const std::string &text = *it; + button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); + button->getSubWidgetText()->setWordWrap(true); + button->setCaption(text); + fitToText(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); + coord.top += button->getHeight(); + this->mButtons.push_back(button); + } + } + + void InfoBoxDialog::open() + { + WindowModal::open(); + // Fix layout + layoutVertically(mTextBox, 4); + layoutVertically(mButtonBar, 6); + layoutVertically(mMainWidget, 4 + 6); + + center(); + } + + int InfoBoxDialog::getChosenButton() const + { + return mCurrentButton; + } + + void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) + { + std::vector::const_iterator end = mButtons.end(); + int i = 0; + for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) + { + if (*it == _sender) + { + mCurrentButton = i; + eventButtonSelected(i); + return; + } + ++i; + } + } + + /* ClassChoiceDialog */ + + ClassChoiceDialog::ClassChoiceDialog() + : InfoBoxDialog() + { + setText(""); + ButtonList buttons; + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); + setButtons(buttons); + } + + /* CreateClassDialog */ + + CreateClassDialog::CreateClassDialog() + : WindowModal("openmw_chargen_create_class.layout") + , mSpecDialog(NULL) + , mAttribDialog(NULL) + , mSkillDialog(NULL) + , mDescDialog(NULL) + { + // Centre dialog + center(); + + setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); + getWidget(mSpecializationName, "SpecializationName"); + mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); + + setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); + getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); + getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); + mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + + setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); + setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); + for(int i = 0; i < 5; i++) + { + char theIndex = '0'+i; + getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); + getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); + mSkills.push_back(mMajorSkill[i]); + mSkills.push_back(mMinorSkill[i]); + } + + std::vector::const_iterator end = mSkills.end(); + for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + { + (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + } + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); + getWidget(mEditName, "EditName"); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); + + MyGUI::Button* descriptionButton; + getWidget(descriptionButton, "DescriptionButton"); + descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); + + // Set default skills, attributes + + mFavoriteAttribute0->setAttributeId(ESM::Attribute::Strength); + mFavoriteAttribute1->setAttributeId(ESM::Attribute::Agility); + + mMajorSkill[0]->setSkillId(ESM::Skill::Block); + mMajorSkill[1]->setSkillId(ESM::Skill::Armorer); + mMajorSkill[2]->setSkillId(ESM::Skill::MediumArmor); + mMajorSkill[3]->setSkillId(ESM::Skill::HeavyArmor); + mMajorSkill[4]->setSkillId(ESM::Skill::BluntWeapon); + + mMinorSkill[0]->setSkillId(ESM::Skill::LongBlade); + mMinorSkill[1]->setSkillId(ESM::Skill::Axe); + mMinorSkill[2]->setSkillId(ESM::Skill::Spear); + mMinorSkill[3]->setSkillId(ESM::Skill::Athletics); + mMinorSkill[4]->setSkillId(ESM::Skill::Enchant); + + setSpecialization(0); + update(); + } + + CreateClassDialog::~CreateClassDialog() + { + delete mSpecDialog; + delete mAttribDialog; + delete mSkillDialog; + delete mDescDialog; + } + + void CreateClassDialog::update() + { + for (int i = 0; i < 5; ++i) + { + ToolTips::createSkillToolTip(mMajorSkill[i], mMajorSkill[i]->getSkillId()); + ToolTips::createSkillToolTip(mMinorSkill[i], mMinorSkill[i]->getSkillId()); + } + + ToolTips::createAttributeToolTip(mFavoriteAttribute0, mFavoriteAttribute0->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute1, mFavoriteAttribute1->getAttributeId()); + } + + std::string CreateClassDialog::getName() const + { + return mEditName->getOnlyText(); + } + + std::string CreateClassDialog::getDescription() const + { + return mDescription; + } + + ESM::Class::Specialization CreateClassDialog::getSpecializationId() const + { + return mSpecializationId; + } + + std::vector CreateClassDialog::getFavoriteAttributes() const + { + std::vector v; + v.push_back(mFavoriteAttribute0->getAttributeId()); + v.push_back(mFavoriteAttribute1->getAttributeId()); + return v; + } + + std::vector CreateClassDialog::getMajorSkills() const + { + std::vector v; + for(int i = 0; i < 5; i++) + { + v.push_back(mMajorSkill[i]->getSkillId()); + } + return v; + } + + std::vector CreateClassDialog::getMinorSkills() const + { + std::vector v; + for(int i=0; i < 5; i++) + { + v.push_back(mMinorSkill[i]->getSkillId()); + } + return v; + } + + void CreateClassDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + // widget controls + + void CreateClassDialog::onDialogCancel() + { + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); + mSpecDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); + mAttribDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); + mSkillDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); + mDescDialog = 0; + } + + void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) + { + delete mSpecDialog; + mSpecDialog = new SelectSpecializationDialog(); + mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); + mSpecDialog->setVisible(true); + } + + void CreateClassDialog::onSpecializationSelected() + { + mSpecializationId = mSpecDialog->getSpecializationId(); + setSpecialization(mSpecializationId); + + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); + mSpecDialog = 0; + } + + void CreateClassDialog::setSpecialization(int id) + { + mSpecializationId = (ESM::Class::Specialization) id; + static const char *specIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); + mSpecializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); + } + + void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) + { + delete mAttribDialog; + mAttribDialog = new SelectAttributeDialog(); + mAffectedAttribute = _sender; + mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); + mAttribDialog->setVisible(true); + } + + void CreateClassDialog::onAttributeSelected() + { + ESM::Attribute::AttributeID id = mAttribDialog->getAttributeId(); + if (mAffectedAttribute == mFavoriteAttribute0) + { + if (mFavoriteAttribute1->getAttributeId() == id) + mFavoriteAttribute1->setAttributeId(mFavoriteAttribute0->getAttributeId()); + } + else if (mAffectedAttribute == mFavoriteAttribute1) + { + if (mFavoriteAttribute0->getAttributeId() == id) + mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); + } + mAffectedAttribute->setAttributeId(id); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); + mAttribDialog = 0; + + update(); + } + + void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) + { + delete mSkillDialog; + mSkillDialog = new SelectSkillDialog(); + mAffectedSkill = _sender; + mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); + mSkillDialog->setVisible(true); + } + + void CreateClassDialog::onSkillSelected() + { + ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); + + // Avoid duplicate skills by swapping any skill field that matches the selected one + std::vector::const_iterator end = mSkills.end(); + for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + { + if (*it == mAffectedSkill) + continue; + if ((*it)->getSkillId() == id) + { + (*it)->setSkillId(mAffectedSkill->getSkillId()); + break; + } + } + + mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); + mSkillDialog = 0; + update(); + } + + void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) + { + mDescDialog = new DescriptionDialog(); + mDescDialog->setTextInput(mDescription); + mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); + mDescDialog->setVisible(true); + } + + void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) + { + mDescription = mDescDialog->getTextInput(); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); + mDescDialog = 0; + } + + void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(getName().size() <= 0) + return; + eventDone(this); + } + + void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + /* SelectSpecializationDialog */ + + SelectSpecializationDialog::SelectSpecializationDialog() + : WindowModal("openmw_chargen_select_specialization.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); + + getWidget(mSpecialization0, "Specialization0"); + getWidget(mSpecialization1, "Specialization1"); + getWidget(mSpecialization2, "Specialization2"); + std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); + std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); + std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + + mSpecialization0->setCaption(combat); + mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecialization1->setCaption(magic); + mSpecialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecialization2->setCaption(stealth); + mSpecialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); mSpecializationId = ESM::Class::Combat; - else if (_sender == mSpecialization1) - mSpecializationId = ESM::Class::Magic; - else if (_sender == mSpecialization2) - mSpecializationId = ESM::Class::Stealth; - else - return; - eventItemSelected(); -} + ToolTips::createSpecializationToolTip(mSpecialization0, combat, ESM::Class::Combat); + ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); + ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); -void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - -/* SelectAttributeDialog */ - -SelectAttributeDialog::SelectAttributeDialog() - : WindowModal("openmw_chargen_select_attribute.layout") -{ - // Centre dialog - center(); - - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); - - for (int i = 0; i < 8; ++i) - { - Widgets::MWAttributePtr attribute; - char theIndex = '0'+i; - - getWidget(attribute, std::string("Attribute").append(1, theIndex)); - attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); - attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); - ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); } - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); -} - -SelectAttributeDialog::~SelectAttributeDialog() -{ -} - -// widget controls - -void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) -{ - // TODO: Change MWAttribute to set and get AttributeID enum instead of int - mAttributeId = static_cast(_sender->getAttributeId()); - eventItemSelected(); -} - -void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - - -/* SelectSkillDialog */ - -SelectSkillDialog::SelectSkillDialog() - : WindowModal("openmw_chargen_select_skill.layout") -{ - // Centre dialog - center(); - - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); - setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); - setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); - setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); - - for(int i = 0; i < 9; i++) + SelectSpecializationDialog::~SelectSpecializationDialog() { - char theIndex = '0'+i; - getWidget(mCombatSkill[i], std::string("CombatSkill").append(1, theIndex)); - getWidget(mMagicSkill[i], std::string("MagicSkill").append(1, theIndex)); - getWidget(mStealthSkill[i], std::string("StealthSkill").append(1, theIndex)); } - struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} mSkills[3][9] = { + // widget controls + + void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender) + { + if (_sender == mSpecialization0) + mSpecializationId = ESM::Class::Combat; + else if (_sender == mSpecialization1) + mSpecializationId = ESM::Class::Magic; + else if (_sender == mSpecialization2) + mSpecializationId = ESM::Class::Stealth; + else + return; + + eventItemSelected(); + } + + void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + /* SelectAttributeDialog */ + + SelectAttributeDialog::SelectAttributeDialog() + : WindowModal("openmw_chargen_select_attribute.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); + + for (int i = 0; i < 8; ++i) { - {mCombatSkill[0], ESM::Skill::Block}, - {mCombatSkill[1], ESM::Skill::Armorer}, - {mCombatSkill[2], ESM::Skill::MediumArmor}, - {mCombatSkill[3], ESM::Skill::HeavyArmor}, - {mCombatSkill[4], ESM::Skill::BluntWeapon}, - {mCombatSkill[5], ESM::Skill::LongBlade}, - {mCombatSkill[6], ESM::Skill::Axe}, - {mCombatSkill[7], ESM::Skill::Spear}, - {mCombatSkill[8], ESM::Skill::Athletics} - }, - { - {mMagicSkill[0], ESM::Skill::Enchant}, - {mMagicSkill[1], ESM::Skill::Destruction}, - {mMagicSkill[2], ESM::Skill::Alteration}, - {mMagicSkill[3], ESM::Skill::Illusion}, - {mMagicSkill[4], ESM::Skill::Conjuration}, - {mMagicSkill[5], ESM::Skill::Mysticism}, - {mMagicSkill[6], ESM::Skill::Restoration}, - {mMagicSkill[7], ESM::Skill::Alchemy}, - {mMagicSkill[8], ESM::Skill::Unarmored} - }, - { - {mStealthSkill[0], ESM::Skill::Security}, - {mStealthSkill[1], ESM::Skill::Sneak}, - {mStealthSkill[2], ESM::Skill::Acrobatics}, - {mStealthSkill[3], ESM::Skill::LightArmor}, - {mStealthSkill[4], ESM::Skill::ShortBlade}, - {mStealthSkill[5] ,ESM::Skill::Marksman}, - {mStealthSkill[6] ,ESM::Skill::Mercantile}, - {mStealthSkill[7] ,ESM::Skill::Speechcraft}, - {mStealthSkill[8] ,ESM::Skill::HandToHand} + Widgets::MWAttributePtr attribute; + char theIndex = '0'+i; + + getWidget(attribute, std::string("Attribute").append(1, theIndex)); + attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); + attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); + ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); } - }; - for (int spec = 0; spec < 3; ++spec) - { - for (int i = 0; i < 9; ++i) - { - mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); - mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); - ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); - } + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); + } + + SelectAttributeDialog::~SelectAttributeDialog() + { + } + + // widget controls + + void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) + { + // TODO: Change MWAttribute to set and get AttributeID enum instead of int + mAttributeId = static_cast(_sender->getAttributeId()); + eventItemSelected(); + } + + void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + + /* SelectSkillDialog */ + + SelectSkillDialog::SelectSkillDialog() + : WindowModal("openmw_chargen_select_skill.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); + setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); + setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); + setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); + + for(int i = 0; i < 9; i++) + { + char theIndex = '0'+i; + getWidget(mCombatSkill[i], std::string("CombatSkill").append(1, theIndex)); + getWidget(mMagicSkill[i], std::string("MagicSkill").append(1, theIndex)); + getWidget(mStealthSkill[i], std::string("StealthSkill").append(1, theIndex)); + } + + struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} mSkills[3][9] = { + { + {mCombatSkill[0], ESM::Skill::Block}, + {mCombatSkill[1], ESM::Skill::Armorer}, + {mCombatSkill[2], ESM::Skill::MediumArmor}, + {mCombatSkill[3], ESM::Skill::HeavyArmor}, + {mCombatSkill[4], ESM::Skill::BluntWeapon}, + {mCombatSkill[5], ESM::Skill::LongBlade}, + {mCombatSkill[6], ESM::Skill::Axe}, + {mCombatSkill[7], ESM::Skill::Spear}, + {mCombatSkill[8], ESM::Skill::Athletics} + }, + { + {mMagicSkill[0], ESM::Skill::Enchant}, + {mMagicSkill[1], ESM::Skill::Destruction}, + {mMagicSkill[2], ESM::Skill::Alteration}, + {mMagicSkill[3], ESM::Skill::Illusion}, + {mMagicSkill[4], ESM::Skill::Conjuration}, + {mMagicSkill[5], ESM::Skill::Mysticism}, + {mMagicSkill[6], ESM::Skill::Restoration}, + {mMagicSkill[7], ESM::Skill::Alchemy}, + {mMagicSkill[8], ESM::Skill::Unarmored} + }, + { + {mStealthSkill[0], ESM::Skill::Security}, + {mStealthSkill[1], ESM::Skill::Sneak}, + {mStealthSkill[2], ESM::Skill::Acrobatics}, + {mStealthSkill[3], ESM::Skill::LightArmor}, + {mStealthSkill[4], ESM::Skill::ShortBlade}, + {mStealthSkill[5] ,ESM::Skill::Marksman}, + {mStealthSkill[6] ,ESM::Skill::Mercantile}, + {mStealthSkill[7] ,ESM::Skill::Speechcraft}, + {mStealthSkill[8] ,ESM::Skill::HandToHand} + } + }; + + for (int spec = 0; spec < 3; ++spec) + { + for (int i = 0; i < 9; ++i) + { + mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); + mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); + ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); + } + } + + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); + } + + SelectSkillDialog::~SelectSkillDialog() + { + } + + // widget controls + + void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender) + { + mSkillId = _sender->getSkillId(); + eventItemSelected(); + } + + void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + /* DescriptionDialog */ + + DescriptionDialog::DescriptionDialog() + : WindowModal("openmw_chargen_class_description.layout") + { + // Centre dialog + center(); + + getWidget(mTextEdit, "TextEdit"); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + } + + DescriptionDialog::~DescriptionDialog() + { + } + + // widget controls + + void DescriptionDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); } - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); -} - -SelectSkillDialog::~SelectSkillDialog() -{ -} - -// widget controls - -void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender) -{ - mSkillId = _sender->getSkillId(); - eventItemSelected(); -} - -void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - -/* DescriptionDialog */ - -DescriptionDialog::DescriptionDialog() - : WindowModal("openmw_chargen_class_description.layout") -{ - // Centre dialog - center(); - - getWidget(mTextEdit, "TextEdit"); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -DescriptionDialog::~DescriptionDialog() -{ -} - -// widget controls - -void DescriptionDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); } diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index bd1b0fe7ab..463c645dc2 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -278,16 +278,15 @@ namespace MWGui std::string Console::complete( std::string input, std::vector &matches ) { - using namespace std; - string output=input; - string tmp=input; + std::string output = input; + std::string tmp = input; bool has_front_quote = false; /* Does the input string contain things that don't have to be completed? If yes erase them. */ /* Are there quotation marks? */ - if( tmp.find('"') != string::npos ) { + if( tmp.find('"') != std::string::npos ) { int numquotes=0; - for(string::iterator it=tmp.begin(); it < tmp.end(); ++it) { + for(std::string::iterator it=tmp.begin(); it < tmp.end(); ++it) { if( *it == '"' ) numquotes++; } @@ -299,7 +298,7 @@ namespace MWGui } else { size_t pos; - if( ( ((pos = tmp.rfind(' ')) != string::npos ) ) && ( pos > tmp.rfind('"') ) ) { + if( ( ((pos = tmp.rfind(' ')) != std::string::npos ) ) && ( pos > tmp.rfind('"') ) ) { tmp.erase( 0, tmp.rfind(' ')+1); } else { @@ -311,7 +310,7 @@ namespace MWGui /* No quotation marks. Are there spaces?*/ else { size_t rpos; - if( (rpos=tmp.rfind(' ')) != string::npos ) { + if( (rpos=tmp.rfind(' ')) != std::string::npos ) { if( rpos == 0 ) { tmp.clear(); } @@ -330,7 +329,7 @@ namespace MWGui } /* Iterate through the vector. */ - for(vector::iterator it=mNames.begin(); it < mNames.end();++it) { + for(std::vector::iterator it=mNames.begin(); it < mNames.end();++it) { bool string_different=false; /* Is the string shorter than the input string? If yes skip it. */ @@ -338,7 +337,7 @@ namespace MWGui continue; /* Is the beginning of the string different from the input string? If yes skip it. */ - for( string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();iter++, iter2++) { + for( std::string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();iter++, iter2++) { if( tolower(*iter) != tolower(*iter2) ) { string_different=true; break; @@ -361,24 +360,24 @@ namespace MWGui /* Only one match. We're done. */ if( matches.size() == 1 ) { /* Adding quotation marks when the input string started with a quotation mark or has spaces in it*/ - if( ( matches.front().find(' ') != string::npos ) ) { + if( ( matches.front().find(' ') != std::string::npos ) ) { if( !has_front_quote ) - output.append(string("\"")); - return output.append(matches.front() + string("\" ")); + output.append(std::string("\"")); + return output.append(matches.front() + std::string("\" ")); } else if( has_front_quote ) { - return output.append(matches.front() + string("\" ")); + return output.append(matches.front() + std::string("\" ")); } else { - return output.append(matches.front() + string(" ")); + return output.append(matches.front() + std::string(" ")); } } /* Check if all matching strings match further than input. If yes complete to this match. */ int i = tmp.length(); - for(string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); iter++, i++) { - for(vector::iterator it=matches.begin(); it < matches.end();++it) { + for(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); iter++, i++) { + for(std::vector::iterator it=matches.begin(); it < matches.end();++it) { if( tolower((*it)[i]) != tolower(*iter) ) { /* Append the longest match to the end of the output string*/ output.append(matches.front().substr( 0, i)); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index d15a5acd3e..16f2535310 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -14,10 +14,6 @@ #include "tradewindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; -using namespace Widgets; - - namespace { bool compareType(std::string type1, std::string type2) @@ -68,686 +64,690 @@ namespace } } - -ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) - : mDragAndDrop(dragAndDrop) - , mFilter(ContainerBase::Filter_All) - , mDisplayEquippedItems(true) - , mHighlightEquippedItems(true) +namespace MWGui { -} -void ContainerBase::setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView) -{ - mContainerWidget = containerWidget; - mItemView = itemView; - - mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); - mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel); -} - -ContainerBase::~ContainerBase() -{ -} - -void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) -{ - mSelectedItem = _sender; - - if (mDragAndDrop && !isTrading()) + ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) + : mDragAndDrop(dragAndDrop) + , mFilter(ContainerBase::Filter_All) + , mDisplayEquippedItems(true) + , mHighlightEquippedItems(true) { - if(!mDragAndDrop->mIsOnDragAndDrop) + } + + void ContainerBase::setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView) + { + mContainerWidget = containerWidget; + mItemView = itemView; + + mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); + mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel); + } + + ContainerBase::~ContainerBase() + { + } + + void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) + { + mSelectedItem = _sender; + + if (mDragAndDrop && !isTrading()) + { + if(!mDragAndDrop->mIsOnDragAndDrop) + { + MWWorld::Ptr object = (*_sender->getUserData()); + int count = object.getRefData().getCount(); + + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + startDragItem(_sender, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + startDragItem(_sender, 1); + } + else + { + std::string message = "#{sTake}"; + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); + } + } + else + onContainerClicked(mContainerWidget); + } + else if (isTrading()) { MWWorld::Ptr object = (*_sender->getUserData()); int count = object.getRefData().getCount(); - if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + if (isInventory()) { - startDragItem(_sender, count); - } - else if (MyGUI::InputManager::getInstance().isControlPressed()) - { - startDragItem(_sender, 1); - } - else - { - std::string message = "#{sTake}"; - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), message, count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); - } - } - else - onContainerClicked(mContainerWidget); - } - else if (isTrading()) - { - MWWorld::Ptr object = (*_sender->getUserData()); - int count = object.getRefData().getCount(); - - if (isInventory()) - { - // the player is trying to sell an item, check if the merchant accepts it - if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) - { - // user notification "i don't buy this item" - MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog4}"); - return; - } - } - - bool buying = isTradeWindow(); // buying or selling? - std::string message = buying ? "#{sQuanityMenuMessage02}" : "#{sQuanityMenuMessage01}"; - - if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) - { - if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) - { - sellAlreadyBoughtItem(NULL, count); - } - else if (MyGUI::InputManager::getInstance().isControlPressed()) - { - sellAlreadyBoughtItem(NULL, 1); - } - else - { - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), message, count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem); - } - } - else - { - if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) - { - sellItem(NULL, count); - } - else if (MyGUI::InputManager::getInstance().isControlPressed()) - { - sellItem(NULL, 1); - } - else - { - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), message, count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); - } - } - } - else - { - onSelectedItemImpl(*_sender->getUserData()); - } -} - -void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) -{ - MWWorld::Ptr object = *mSelectedItem->getUserData(); - - if (isInventory()) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); - } - else - { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); - } - - std::string sound = MWWorld::Class::get(object).getUpSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - drawItems(); -} - -void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) -{ - MWWorld::Ptr object = *mSelectedItem->getUserData(); - - if (isInventory()) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); - } - else - { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); - } - - std::string sound = MWWorld::Class::get(object).getUpSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - drawItems(); -} - -void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count) -{ - mDragAndDrop->mIsOnDragAndDrop = true; - mSelectedItem->detachFromWidget(); - mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); - - MWWorld::Ptr object = *mSelectedItem->getUserData(); - _unequipItem(object); - - mDragAndDrop->mDraggedCount = count; - - mDragAndDrop->mDraggedFrom = this; - - std::string sound = MWWorld::Class::get(object).getUpSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - mDragAndDrop->mDraggedWidget = mSelectedItem; - static_cast(mSelectedItem)->setImageTexture(""); // remove the background texture (not visible during drag) - static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( - getCountString(mDragAndDrop->mDraggedCount)); - - drawItems(); - - MWBase::Environment::get().getWindowManager()->setDragDrop(true); -} - -void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) -{ - if (mDragAndDrop == NULL) return; - - if(mDragAndDrop->mIsOnDragAndDrop) //drop item here - { - MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - if (mDragAndDrop->mDraggedFrom != this) - { - assert(object.getContainerStore() && "Item is not in a container!"); - - // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside - if (mPtr.getTypeName() == typeid(ESM::Container).name()) - { - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mFlags & ESM::Container::Organic) + // the player is trying to sell an item, check if the merchant accepts it + if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) { - // user notification + // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage2}"); - + messageBox("#{sBarterDialog4}"); return; } } - int origCount = object.getRefData().getCount(); + bool buying = isTradeWindow(); // buying or selling? + std::string message = buying ? "#{sQuanityMenuMessage02}" : "#{sQuanityMenuMessage01}"; - // check that we don't exceed the allowed weight (only for containers, not for inventory) - if (!isInventory()) + if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) { - float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr); - - // try adding the item, and if weight is exceeded, just remove it again. - object.getRefData().setCount(mDragAndDrop->mDraggedCount); - MWWorld::ContainerStoreIterator it = containerStore.add(object); - - float curWeight = MWWorld::Class::get(mPtr).getEncumbrance(mPtr); - if (curWeight > capacity) + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) { - it->getRefData().setCount(0); - object.getRefData().setCount(origCount); - // user notification - MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage3}"); - - return; + sellAlreadyBoughtItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellAlreadyBoughtItem(NULL, 1); } else { - object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem); } } else { - object.getRefData().setCount (mDragAndDrop->mDraggedCount); - containerStore.add(object); - object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + sellItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellItem(NULL, 1); + } + else + { + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); + } } } + else + { + onSelectedItemImpl(*_sender->getUserData()); + } + } - mDragAndDrop->mIsOnDragAndDrop = false; - MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - drawItems(); - mDragAndDrop->mDraggedFrom->drawItems(); + void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) + { + MWWorld::Ptr object = *mSelectedItem->getUserData(); - mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); - notifyItemDragged(object, mDragAndDrop->mDraggedCount); + if (isInventory()) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); + } + else + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + } - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - - std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - } -} -void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mItemView->getViewOffset().left + _rel*0.3 > 0) - mItemView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0)); -} - -void ContainerBase::setFilter(int filter) -{ - mFilter = filter; - drawItems(); -} - -void ContainerBase::openContainer(MWWorld::Ptr container) -{ - mPtr = container; -} - -void ContainerBase::drawItems() -{ - while (mContainerWidget->getChildCount()) - { - MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); - } - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - int x = 0; - int y = 0; - int maxHeight = mItemView->getSize().height - 58; - - bool onlyMagic = false; - bool noMagic = false; - int categories = 0; - if (mFilter & Filter_All) - categories |= MWWorld::ContainerStore::Type_All; - if (mFilter & Filter_Weapon) - categories |= MWWorld::ContainerStore::Type_Weapon; - if (mFilter & Filter_Apparel) - categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor; - if (mFilter & Filter_Magic) - { - categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor - | MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Book - | MWWorld::ContainerStore::Type_Potion; - onlyMagic = true; - } - if (mFilter & Filter_Misc) - { - categories |= MWWorld::ContainerStore::Type_Miscellaneous | MWWorld::ContainerStore::Type_Book - | MWWorld::ContainerStore::Type_Ingredient | MWWorld::ContainerStore::Type_Repair - | MWWorld::ContainerStore::Type_Lockpick | MWWorld::ContainerStore::Type_Light - | MWWorld::ContainerStore::Type_Apparatus | MWWorld::ContainerStore::Type_Probe; - } - if (mFilter & Filter_Ingredients) - categories |= MWWorld::ContainerStore::Type_Ingredient; - if (mFilter & Filter_ChargedSoulstones) - categories |= MWWorld::ContainerStore::Type_Miscellaneous; - if (mFilter & Filter_NoMagic) - noMagic = true; - - /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them - - std::vector< std::pair > items; - - std::vector equippedItems = getEquippedItems(); - - // add bought items (always at the beginning) - std::vector boughtItems; - for (MWWorld::ContainerStoreIterator it (mBoughtItems.begin()); it!=mBoughtItems.end(); ++it) - { - boughtItems.push_back(*it); - } - std::sort(boughtItems.begin(), boughtItems.end(), sortItems); - - for (std::vector::iterator it=boughtItems.begin(); - it != boughtItems.end(); ++it) - { - items.push_back( std::make_pair(*it, ItemState_Barter) ); + drawItems(); } - // filter out the equipped items of categories we don't want - std::vector unwantedItems = equippedItems; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) { - std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *iter); - if (found != unwantedItems.end()) + MWWorld::Ptr object = *mSelectedItem->getUserData(); + + if (isInventory()) { - unwantedItems.erase(found); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } - } - // now erase everything that's still in unwantedItems. - for (std::vector::iterator it=unwantedItems.begin(); - it != unwantedItems.end(); ++it) - { - std::vector::iterator found = std::find(equippedItems.begin(), equippedItems.end(), *it); - assert(found != equippedItems.end()); - equippedItems.erase(found); - } - // and add the items that are left (= have the correct category) - if (mDisplayEquippedItems && mHighlightEquippedItems) - { - for (std::vector::const_iterator it=equippedItems.begin(); - it != equippedItems.end(); ++it) + else { - items.push_back( std::make_pair(*it, ItemState_Equipped) ); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + drawItems(); } - std::vector ignoreItems = itemsToIgnore(); - - // now add the regular items - std::vector regularItems; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count) { - if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() - || (!mHighlightEquippedItems && mDisplayEquippedItems)) - && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() - && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) - regularItems.push_back(*iter); + mDragAndDrop->mIsOnDragAndDrop = true; + mSelectedItem->detachFromWidget(); + mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); + + MWWorld::Ptr object = *mSelectedItem->getUserData(); + _unequipItem(object); + + mDragAndDrop->mDraggedCount = count; + + mDragAndDrop->mDraggedFrom = this; + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + mDragAndDrop->mDraggedWidget = mSelectedItem; + static_cast(mSelectedItem)->setImageTexture(""); // remove the background texture (not visible during drag) + static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( + getCountString(mDragAndDrop->mDraggedCount)); + + drawItems(); + + MWBase::Environment::get().getWindowManager()->setDragDrop(true); } - // sort them and add - std::sort(regularItems.begin(), regularItems.end(), sortItems); - for (std::vector::const_iterator it=regularItems.begin(); it!=regularItems.end(); ++it) + void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { - items.push_back( std::make_pair(*it, ItemState_Normal) ); - } + if (mDragAndDrop == NULL) return; - for (std::vector< std::pair >::const_iterator it=items.begin(); - it != items.end(); ++it) - { - const MWWorld::Ptr* iter = &((*it).first); - - - if (onlyMagic - && it->second != ItemState_Barter - && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" - && iter->getTypeName() != typeid(ESM::Potion).name()) - continue; - - if (noMagic - && it->second != ItemState_Barter - && (MWWorld::Class::get(*iter).getEnchantment(*iter) != "" - || iter->getTypeName() == typeid(ESM::Potion).name())) - continue; - - if ( (mFilter & Filter_ChargedSoulstones) - && !isChargedSoulstone(*iter)) - continue; - - int displayCount = iter->getRefData().getCount(); - if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + if(mDragAndDrop->mIsOnDragAndDrop) //drop item here { - displayCount -= mDragAndDrop->mDraggedCount; - } - if(displayCount > 0) - { - std::string path = std::string("icons\\"); - path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - // background widget (for the "equipped" frame and magic item background image) - bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); - MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); - backgroundWidget->setUserString("ToolTipType", "ItemPtr"); - backgroundWidget->setUserData(*iter); - - std::string backgroundTex = "textures\\menu_icon"; - if (isMagic) - backgroundTex += "_magic"; - if (it->second == ItemState_Normal) + if (mDragAndDrop->mDraggedFrom != this) { - if (!isMagic) - backgroundTex = ""; - } - else if (it->second == ItemState_Equipped) - { - backgroundTex += "_equip"; - } - else if (it->second == ItemState_Barter) - { - backgroundTex += "_barter"; - } - if (backgroundTex != "") - backgroundTex += ".dds"; + assert(object.getContainerStore() && "Item is not in a container!"); - backgroundWidget->setImageTexture(backgroundTex); - if (it->second == ItemState_Barter && !isMagic) - backgroundWidget->setProperty("ImageCoord", "2 2 42 42"); - else - backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); - backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem); - backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel); + // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside + if (mPtr.getTypeName() == typeid(ESM::Container).name()) + { + MWWorld::LiveCellRef* ref = mPtr.get(); + if (ref->mBase->mFlags & ESM::Container::Organic) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sContentsMessage2}"); - // image - MyGUI::ImageBox* image = backgroundWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - image->setImageTexture(path); - image->setNeedMouseFocus(false); + return; + } + } - // text widget that shows item count - MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); - text->setTextAlign(MyGUI::Align::Right); - text->setNeedMouseFocus(false); - text->setTextShadow(true); - text->setTextShadowColour(MyGUI::Colour(0,0,0)); - text->setCaption(getCountString(displayCount)); + int origCount = object.getRefData().getCount(); - y += 42; - if (y > maxHeight) - { - x += 42; - y = 0; + // check that we don't exceed the allowed weight (only for containers, not for inventory) + if (!isInventory()) + { + float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr); + + // try adding the item, and if weight is exceeded, just remove it again. + object.getRefData().setCount(mDragAndDrop->mDraggedCount); + MWWorld::ContainerStoreIterator it = containerStore.add(object); + + float curWeight = MWWorld::Class::get(mPtr).getEncumbrance(mPtr); + if (curWeight > capacity) + { + it->getRefData().setCount(0); + object.getRefData().setCount(origCount); + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sContentsMessage3}"); + + return; + } + else + { + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + } + } + else + { + object.getRefData().setCount (mDragAndDrop->mDraggedCount); + containerStore.add(object); + object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); + } } + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + drawItems(); + mDragAndDrop->mDraggedFrom->drawItems(); + + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); + notifyItemDragged(object, mDragAndDrop->mDraggedCount); + + MWBase::Environment::get().getWindowManager()->setDragDrop(false); + + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } } - MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); - mItemView->setCanvasSize(size); - mContainerWidget->setSize(size); - - notifyContentChanged(); -} - -std::string ContainerBase::getCountString(const int count) -{ - if (count == 1) - return ""; - if (count > 9999) - return boost::lexical_cast(int(count/1000.f)) + "k"; - else - return boost::lexical_cast(count); -} - -void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) -{ - int origCount = item.getRefData().getCount(); - item.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = mBoughtItems.add(item); - item.getRefData().setCount(origCount - count); -} - -void ContainerBase::addItem(MWWorld::Ptr item, int count) -{ - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - int origCount = item.getRefData().getCount(); - - item.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = containerStore.add(item); - - item.getRefData().setCount(origCount - count); -} - -void ContainerBase::transferBoughtItems() -{ - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - containerStore.add(*it); + if (mItemView->getViewOffset().left + _rel*0.3 > 0) + mItemView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0)); } -} -void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) -{ - for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + void ContainerBase::setFilter(int filter) { - store.add(*it); + mFilter = filter; + drawItems(); } -} -std::vector ContainerBase::getEquippedItems() -{ - if (mPtr.getTypeName() != typeid(ESM::NPC).name()) - return std::vector(); - - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - - std::vector items; - - for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + void ContainerBase::openContainer(MWWorld::Ptr container) { - MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); - if (it != invStore.end()) + mPtr = container; + } + + void ContainerBase::drawItems() + { + while (mContainerWidget->getChildCount()) { - items.push_back(*it); + MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); } - } - - return items; -} - -MWWorld::ContainerStore& ContainerBase::getContainerStore() -{ - MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - return store; -} - -// ------------------------------------------------------------------------------------------------ - -ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) - : ContainerBase(dragAndDrop) - , WindowBase("openmw_container_window.layout") -{ - getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); - getWidget(mTakeButton, "TakeButton"); - getWidget(mCloseButton, "CloseButton"); - - MyGUI::ScrollView* itemView; - MyGUI::Widget* containerWidget; - getWidget(containerWidget, "Items"); - getWidget(itemView, "ItemView"); - setWidgets(containerWidget, itemView); - - mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); - - static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); - - setCoord(200,0,600,300); -} - -ContainerWindow::~ContainerWindow() -{ -} - -void ContainerWindow::onWindowResize(MyGUI::Window* window) -{ - drawItems(); -} - -void ContainerWindow::open(MWWorld::Ptr container, bool loot) -{ - mDisplayEquippedItems = true; - mHighlightEquippedItems = false; - if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) - { - // we are stealing stuff - mDisplayEquippedItems = false; - } - - mDisposeCorpseButton->setVisible(loot); - - openContainer(container); - setTitle(MWWorld::Class::get(container).getName(container)); - drawItems(); -} - -void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); - } -} - -void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - // transfer everything into the player's inventory MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + int x = 0; + int y = 0; + int maxHeight = mItemView->getSize().height - 58; + + bool onlyMagic = false; + bool noMagic = false; + int categories = 0; + if (mFilter & Filter_All) + categories |= MWWorld::ContainerStore::Type_All; + if (mFilter & Filter_Weapon) + categories |= MWWorld::ContainerStore::Type_Weapon; + if (mFilter & Filter_Apparel) + categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor; + if (mFilter & Filter_Magic) + { + categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor + | MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Book + | MWWorld::ContainerStore::Type_Potion; + onlyMagic = true; + } + if (mFilter & Filter_Misc) + { + categories |= MWWorld::ContainerStore::Type_Miscellaneous | MWWorld::ContainerStore::Type_Book + | MWWorld::ContainerStore::Type_Ingredient | MWWorld::ContainerStore::Type_Repair + | MWWorld::ContainerStore::Type_Lockpick | MWWorld::ContainerStore::Type_Light + | MWWorld::ContainerStore::Type_Apparatus | MWWorld::ContainerStore::Type_Probe; + } + if (mFilter & Filter_Ingredients) + categories |= MWWorld::ContainerStore::Type_Ingredient; + if (mFilter & Filter_ChargedSoulstones) + categories |= MWWorld::ContainerStore::Type_Miscellaneous; + if (mFilter & Filter_NoMagic) + noMagic = true; + + /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them + + std::vector< std::pair > items; + std::vector equippedItems = getEquippedItems(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); - - int i=0; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + // add bought items (always at the beginning) + std::vector boughtItems; + for (MWWorld::ContainerStoreIterator it (mBoughtItems.begin()); it!=mBoughtItems.end(); ++it) { - if (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() - && !mDisplayEquippedItems) - continue; + boughtItems.push_back(*it); + } + std::sort(boughtItems.begin(), boughtItems.end(), sortItems); - playerStore.add(*iter); - - if (i==0) - { - // play the sound of the first object - std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - } - - iter->getRefData().setCount(0); - - ++i; + for (std::vector::iterator it=boughtItems.begin(); + it != boughtItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Barter) ); } + // filter out the equipped items of categories we don't want + std::vector unwantedItems = equippedItems; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + { + std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *iter); + if (found != unwantedItems.end()) + { + unwantedItems.erase(found); + } + } + // now erase everything that's still in unwantedItems. + for (std::vector::iterator it=unwantedItems.begin(); + it != unwantedItems.end(); ++it) + { + std::vector::iterator found = std::find(equippedItems.begin(), equippedItems.end(), *it); + assert(found != equippedItems.end()); + equippedItems.erase(found); + } + // and add the items that are left (= have the correct category) + if (mDisplayEquippedItems && mHighlightEquippedItems) + { + for (std::vector::const_iterator it=equippedItems.begin(); + it != equippedItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Equipped) ); + } + } + + std::vector ignoreItems = itemsToIgnore(); + + // now add the regular items + std::vector regularItems; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + { + if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() + || (!mHighlightEquippedItems && mDisplayEquippedItems)) + && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() + && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) + regularItems.push_back(*iter); + } + + // sort them and add + std::sort(regularItems.begin(), regularItems.end(), sortItems); + for (std::vector::const_iterator it=regularItems.begin(); it!=regularItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Normal) ); + } + + for (std::vector< std::pair >::const_iterator it=items.begin(); + it != items.end(); ++it) + { + const MWWorld::Ptr* iter = &((*it).first); + + + if (onlyMagic + && it->second != ItemState_Barter + && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" + && iter->getTypeName() != typeid(ESM::Potion).name()) + continue; + + if (noMagic + && it->second != ItemState_Barter + && (MWWorld::Class::get(*iter).getEnchantment(*iter) != "" + || iter->getTypeName() == typeid(ESM::Potion).name())) + continue; + + if ( (mFilter & Filter_ChargedSoulstones) + && !isChargedSoulstone(*iter)) + continue; + + int displayCount = iter->getRefData().getCount(); + if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + { + displayCount -= mDragAndDrop->mDraggedCount; + } + if(displayCount > 0) + { + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + + // background widget (for the "equipped" frame and magic item background image) + bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); + MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); + backgroundWidget->setUserString("ToolTipType", "ItemPtr"); + backgroundWidget->setUserData(*iter); + + std::string backgroundTex = "textures\\menu_icon"; + if (isMagic) + backgroundTex += "_magic"; + if (it->second == ItemState_Normal) + { + if (!isMagic) + backgroundTex = ""; + } + else if (it->second == ItemState_Equipped) + { + backgroundTex += "_equip"; + } + else if (it->second == ItemState_Barter) + { + backgroundTex += "_barter"; + } + if (backgroundTex != "") + backgroundTex += ".dds"; + + backgroundWidget->setImageTexture(backgroundTex); + if (it->second == ItemState_Barter && !isMagic) + backgroundWidget->setProperty("ImageCoord", "2 2 42 42"); + else + backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); + backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem); + backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel); + + // image + MyGUI::ImageBox* image = backgroundWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture(path); + image->setNeedMouseFocus(false); + + // text widget that shows item count + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); + text->setTextAlign(MyGUI::Align::Right); + text->setNeedMouseFocus(false); + text->setTextShadow(true); + text->setTextShadowColour(MyGUI::Colour(0,0,0)); + text->setCaption(getCountString(displayCount)); + + y += 42; + if (y > maxHeight) + { + x += 42; + y = 0; + } + + } + } + + MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); + mItemView->setCanvasSize(size); + mContainerWidget->setSize(size); + + notifyContentChanged(); + } + + std::string ContainerBase::getCountString(const int count) + { + if (count == 1) + return ""; + if (count > 9999) + return boost::lexical_cast(int(count/1000.f)) + "k"; + else + return boost::lexical_cast(count); + } + + void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) + { + int origCount = item.getRefData().getCount(); + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = mBoughtItems.add(item); + item.getRefData().setCount(origCount - count); + } + + void ContainerBase::addItem(MWWorld::Ptr item, int count) + { + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + int origCount = item.getRefData().getCount(); + + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = containerStore.add(item); + + item.getRefData().setCount(origCount - count); + } + + void ContainerBase::transferBoughtItems() + { + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + containerStore.add(*it); + } + } + + void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) + { + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + store.add(*it); + } + } + + std::vector ContainerBase::getEquippedItems() + { + if (mPtr.getTypeName() != typeid(ESM::NPC).name()) + return std::vector(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + + std::vector items; + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) + { + items.push_back(*it); + } + } + + return items; + } + + MWWorld::ContainerStore& ContainerBase::getContainerStore() + { + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + return store; + } + + // ------------------------------------------------------------------------------------------------ + + ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) + : ContainerBase(dragAndDrop) + , WindowBase("openmw_container_window.layout") + { + getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); + getWidget(mTakeButton, "TakeButton"); + getWidget(mCloseButton, "CloseButton"); + + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); + + setCoord(200,0,600,300); + } + + ContainerWindow::~ContainerWindow() + { + } + + void ContainerWindow::onWindowResize(MyGUI::Window* window) + { + drawItems(); + } + + void ContainerWindow::open(MWWorld::Ptr container, bool loot) + { + mDisplayEquippedItems = true; + mHighlightEquippedItems = false; + if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) + { + // we are stealing stuff + mDisplayEquippedItems = false; + } + + mDisposeCorpseButton->setVisible(loot); + + openContainer(container); + setTitle(MWWorld::Class::get(container).getName(container)); + drawItems(); + } + + void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } + } + + void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + // transfer everything into the player's inventory + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + std::vector equippedItems = getEquippedItems(); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); + + int i=0; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + { + if (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() + && !mDisplayEquippedItems) + continue; + + playerStore.add(*iter); + + if (i==0) + { + // play the sound of the first object + std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + } + + iter->getRefData().setCount(0); + + ++i; + } + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } + } + + void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + onTakeAllButtonClicked(mTakeButton); + + /// \todo I don't think this is the correct flag to check + if (MWWorld::Class::get(mPtr).isEssential(mPtr)) + MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); + else + MWBase::Environment::get().getWorld()->deleteObject(mPtr); + + mPtr = MWWorld::Ptr(); + } + } + + void ContainerWindow::onReferenceUnavailable() + { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } -} - -void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - onTakeAllButtonClicked(mTakeButton); - - /// \todo I don't think this is the correct flag to check - if (MWWorld::Class::get(mPtr).isEssential(mPtr)) - MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); - else - MWBase::Environment::get().getWorld()->deleteObject(mPtr); - - mPtr = MWWorld::Ptr(); - } -} - -void ContainerWindow::onReferenceUnavailable() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 392f641264..b596cef018 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -19,521 +19,521 @@ #include "inventorywindow.hpp" #include "travelwindow.hpp" -using namespace MWGui; -using namespace Widgets; - /** *Copied from the internet. */ -namespace { - -std::string lower_string(const std::string& str) +namespace { - std::string lowerCase = Misc::StringUtils::lowerCase (str); - return lowerCase; -} - -std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) -{ - return lower_string(str).find(lower_string(substr),pos); -} - -bool sortByLength (const std::string& left, const std::string& right) -{ - return left.size() > right.size(); -} -} - - - -PersuasionDialog::PersuasionDialog() - : WindowModal("openmw_persuasion_dialog.layout") -{ - getWidget(mCancelButton, "CancelButton"); - getWidget(mAdmireButton, "AdmireButton"); - getWidget(mIntimidateButton, "IntimidateButton"); - getWidget(mTauntButton, "TauntButton"); - getWidget(mBribe10Button, "Bribe10Button"); - getWidget(mBribe100Button, "Bribe100Button"); - getWidget(mBribe1000Button, "Bribe1000Button"); - getWidget(mGoldLabel, "GoldLabel"); - - mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); - mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); -} - -void PersuasionDialog::onCancel(MyGUI::Widget *sender) -{ - setVisible(false); -} - -void PersuasionDialog::onPersuade(MyGUI::Widget *sender) -{ - MWBase::MechanicsManager::PersuasionType type; - if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; - else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; - else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; - else if (sender == mBribe10Button) + std::string lower_string(const std::string& str) { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); - type = MWBase::MechanicsManager::PT_Bribe10; - } - else if (sender == mBribe100Button) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); - type = MWBase::MechanicsManager::PT_Bribe100; - } - else /*if (sender == mBribe1000Button)*/ - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); - type = MWBase::MechanicsManager::PT_Bribe1000; + std::string lowerCase = Misc::StringUtils::lowerCase (str); + + return lowerCase; } - MWBase::Environment::get().getDialogueManager()->persuade(type); - - setVisible(false); -} - -void PersuasionDialog::open() -{ - WindowModal::open(); - center(); - - int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); - - mBribe10Button->setEnabled (playerGold >= 10); - mBribe100Button->setEnabled (playerGold >= 100); - mBribe1000Button->setEnabled (playerGold >= 1000); - - mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); -} - -// -------------------------------------------------------------------------------------------------- - -DialogueWindow::DialogueWindow() - : WindowBase("openmw_dialogue_window.layout") - , mPersuasionDialog() - , mEnabled(false) - , mServices(0) -{ - // Centre dialog - center(); - - mPersuasionDialog.setVisible(false); - - //History view - getWidget(mHistory, "History"); - mHistory->setOverflowToTheLeft(true); - mHistory->setMaxTextLength(1000000); - MyGUI::Widget* eventbox; - - //An EditBox cannot receive mouse click events, so we use an - //invisible widget on top of the editbox to receive them - getWidget(eventbox, "EventBox"); - eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); - eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); - - //Topics list - getWidget(mTopicsList, "TopicsList"); - mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); - byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); - - getWidget(mDispositionBar, "Disposition"); - getWidget(mDispositionText,"DispositionText"); - - static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); -} - -void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) -{ - MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); - if(t == NULL) - return; - - const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); - - size_t cursorPosition = t->getCursorPosition(lastPressed); - MyGUI::UString color = mHistory->getColorAtPos(cursorPosition); - - if (!mEnabled && color == "#572D21") - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - - if (!mEnabled) - return; - - if(color != "#B29154") + std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) { - MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); + return lower_string(str).find(lower_string(substr),pos); + } - if(color == "#686EBA") + bool sortByLength (const std::string& left, const std::string& right) + { + return left.size() > right.size(); + } +} + +namespace MWGui +{ + + PersuasionDialog::PersuasionDialog() + : WindowModal("openmw_persuasion_dialog.layout") + { + getWidget(mCancelButton, "CancelButton"); + getWidget(mAdmireButton, "AdmireButton"); + getWidget(mIntimidateButton, "IntimidateButton"); + getWidget(mTauntButton, "TauntButton"); + getWidget(mBribe10Button, "Bribe10Button"); + getWidget(mBribe100Button, "Bribe100Button"); + getWidget(mBribe1000Button, "Bribe1000Button"); + getWidget(mGoldLabel, "GoldLabel"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); + mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + } + + void PersuasionDialog::onCancel(MyGUI::Widget *sender) + { + setVisible(false); + } + + void PersuasionDialog::onPersuade(MyGUI::Widget *sender) + { + MWBase::MechanicsManager::PersuasionType type; + if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; + else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; + else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; + else if (sender == mBribe10Button) { - std::map::iterator i = mHyperLinks.upper_bound(cursorPosition); - if( !mHyperLinks.empty() ) - { - --i; - - if( i->first + i->second.mLength > cursorPosition) - { - MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue); - } - } - else - { - // the link was colored, but it is not in mHyperLinks. - // It means that those liunks are not marked with @# and found - // by topic name search - MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); - } + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); + type = MWBase::MechanicsManager::PT_Bribe10; + } + else if (sender == mBribe100Button) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); + type = MWBase::MechanicsManager::PT_Bribe100; + } + else /*if (sender == mBribe1000Button)*/ + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); + type = MWBase::MechanicsManager::PT_Bribe1000; } - if(color == "#572D21") - MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); - } -} + MWBase::Environment::get().getDialogueManager()->persuade(type); -void DialogueWindow::onWindowResize(MyGUI::Window* _sender) -{ - mTopicsList->adjustSize(); -} - -void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mHistory->getVScrollPosition() - _rel*0.3 < 0) - mHistory->setVScrollPosition(0); - else - mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3); -} - -void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); -} - -void DialogueWindow::onSelectTopic(const std::string& topic, int id) -{ - if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) - return; - - int separatorPos = 0; - for (unsigned int i=0; igetItemCount(); ++i) - { - if (mTopicsList->getItemNameAt(i) == "") - separatorPos = i; + setVisible(false); } - if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); - else + void PersuasionDialog::open() { + WindowModal::open(); + center(); + + int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); + + mBribe10Button->setEnabled (playerGold >= 10); + mBribe100Button->setEnabled (playerGold >= 100); + mBribe1000Button->setEnabled (playerGold >= 1000); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + } + + // -------------------------------------------------------------------------------------------------- + + DialogueWindow::DialogueWindow() + : WindowBase("openmw_dialogue_window.layout") + , mPersuasionDialog() + , mEnabled(false) + , mServices(0) + { + // Centre dialog + center(); + + mPersuasionDialog.setVisible(false); + + //History view + getWidget(mHistory, "History"); + mHistory->setOverflowToTheLeft(true); + mHistory->setMaxTextLength(1000000); + MyGUI::Widget* eventbox; + + //An EditBox cannot receive mouse click events, so we use an + //invisible widget on top of the editbox to receive them + getWidget(eventbox, "EventBox"); + eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); + eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); + + //Topics list + getWidget(mTopicsList, "TopicsList"); + mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + + MyGUI::Button* byeButton; + getWidget(byeButton, "ByeButton"); + byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); + + getWidget(mDispositionBar, "Disposition"); + getWidget(mDispositionText,"DispositionText"); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); + } + + void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) + { + MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); + if(t == NULL) + return; + + const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + + size_t cursorPosition = t->getCursorPosition(lastPressed); + MyGUI::UString color = mHistory->getColorAtPos(cursorPosition); + + if (!mEnabled && color == "#572D21") + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + + if (!mEnabled) + return; + + if(color != "#B29154") + { + MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); + + if(color == "#686EBA") + { + std::map::iterator i = mHyperLinks.upper_bound(cursorPosition); + if( !mHyperLinks.empty() ) + { + --i; + + if( i->first + i->second.mLength > cursorPosition) + { + MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue); + } + } + else + { + // the link was colored, but it is not in mHyperLinks. + // It means that those liunks are not marked with @# and found + // by topic name search + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); + } + } + + if(color == "#572D21") + MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); + } + } + + void DialogueWindow::onWindowResize(MyGUI::Window* _sender) + { + mTopicsList->adjustSize(); + } + + void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mHistory->getVScrollPosition() - _rel*0.3 < 0) + mHistory->setVScrollPosition(0); + else + mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3); + } + + void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) + { + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + } + + void DialogueWindow::onSelectTopic(const std::string& topic, int id) + { + if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + return; + + int separatorPos = 0; + for (unsigned int i=0; igetItemCount(); ++i) + { + if (mTopicsList->getItemNameAt(i) == "") + separatorPos = i; + } + + if (id >= separatorPos) + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); + else + { + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (topic == gmst.find("sPersuasion")->getString()) + { + mPersuasionDialog.setVisible(true); + } + else if (topic == gmst.find("sCompanionShare")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); + MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + } + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + { + if (topic == gmst.find("sBarter")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); + } + else if (topic == gmst.find("sSpells")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); + } + else if (topic == gmst.find("sTravel")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); + } + else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); + } + else if (topic == gmst.find("sEnchanting")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); + MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); + } + else if (topic == gmst.find("sServiceTrainingTitle")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->startTraining (mPtr); + } + else if (topic == gmst.find("sRepair")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + } + } + } + } + + void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) + { + mEnabled = true; + mPtr = actor; + mTopicsList->setEnabled(true); + setTitle(npcName); + + mTopicsList->clear(); + mHyperLinks.clear(); + mHistory->setCaption(""); + updateOptions(); + } + + void DialogueWindow::setKeywords(std::list keyWords) + { + mTopicsList->clear(); + + bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty() + && mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion"); + + bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); + const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (topic == gmst.find("sPersuasion")->getString()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + mTopicsList->addItem(gmst.find("sPersuasion")->getString()); + + if (mServices & Service_Trade) + mTopicsList->addItem(gmst.find("sBarter")->getString()); + + if (mServices & Service_BuySpells) + mTopicsList->addItem(gmst.find("sSpells")->getString()); + + if (mServices & Service_Travel) + mTopicsList->addItem(gmst.find("sTravel")->getString()); + + if (mServices & Service_CreateSpells) + mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); + + if (mServices & Service_Enchant) + mTopicsList->addItem(gmst.find("sEnchanting")->getString()); + + if (mServices & Service_Training) + mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); + + if (mServices & Service_Repair) + mTopicsList->addItem(gmst.find("sRepair")->getString()); + + if (isCompanion) + mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); + + if (anyService) + mTopicsList->addSeparator(); + + + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) { - mPersuasionDialog.setVisible(true); + mTopicsList->addItem(*it); } - else if (topic == gmst.find("sCompanionShare")->getString()) + mTopicsList->adjustSize(); + } + + void DialogueWindow::removeKeyword(std::string keyWord) + { + if(mTopicsList->hasItem(keyWord)) { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + mTopicsList->removeItem(keyWord); } - else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + mTopicsList->adjustSize(); + } + + void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) + { + size_t pos = 0; + while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) { - if (topic == gmst.find("sBarter")->getString()) + // do not add color if this portion of text is already colored. { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); - } - else if (topic == gmst.find("sSpells")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); - } - else if (topic == gmst.find("sTravel")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); - } - else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); - MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); - } - else if (topic == gmst.find("sEnchanting")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); - MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); - } - else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); - MWBase::Environment::get().getWindowManager()->startTraining (mPtr); - } - else if (topic == gmst.find("sRepair")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); - MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + MyGUI::TextIterator iterator (str); + MyGUI::UString colour; + while(iterator.moveNext()) + { + size_t iteratorPos = iterator.getPosition(); + iterator.getTagColour(colour); + if (iteratorPos == pos) + break; + } + + if (colour == color1) + return; } + + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); } } -} -void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) -{ - mEnabled = true; - mPtr = actor; - mTopicsList->setEnabled(true); - setTitle(npcName); - - mTopicsList->clear(); - mHyperLinks.clear(); - mHistory->setCaption(""); - updateOptions(); -} - -void DialogueWindow::setKeywords(std::list keyWords) -{ - mTopicsList->clear(); - - bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion"); - - bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); - - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) - mTopicsList->addItem(gmst.find("sPersuasion")->getString()); - - if (mServices & Service_Trade) - mTopicsList->addItem(gmst.find("sBarter")->getString()); - - if (mServices & Service_BuySpells) - mTopicsList->addItem(gmst.find("sSpells")->getString()); - - if (mServices & Service_Travel) - mTopicsList->addItem(gmst.find("sTravel")->getString()); - - if (mServices & Service_CreateSpells) - mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); - - if (mServices & Service_Enchant) - mTopicsList->addItem(gmst.find("sEnchanting")->getString()); - - if (mServices & Service_Training) - mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); - - if (mServices & Service_Repair) - mTopicsList->addItem(gmst.find("sRepair")->getString()); - - if (isCompanion) - mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); - - if (anyService) - mTopicsList->addSeparator(); - - - for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) + std::string DialogueWindow::parseText(const std::string& text) { - mTopicsList->addItem(*it); - } - mTopicsList->adjustSize(); -} + bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) -void DialogueWindow::removeKeyword(std::string keyWord) -{ - if(mTopicsList->hasItem(keyWord)) - { - mTopicsList->removeItem(keyWord); - } - mTopicsList->adjustSize(); -} + std::vector topics; -void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) -{ - size_t pos = 0; - while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) - { - // do not add color if this portion of text is already colored. + bool hasSeparator = false; + for (unsigned int i=0; igetItemCount(); ++i) { - MyGUI::TextIterator iterator (str); - MyGUI::UString colour; - while(iterator.moveNext()) - { - size_t iteratorPos = iterator.getPosition(); - iterator.getTagColour(colour); - if (iteratorPos == pos) - break; - } - - if (colour == color1) - return; + if (mTopicsList->getItemNameAt(i) == "") + hasSeparator = true; } - str.insert(pos,color1); - pos += color1.length(); - pos += keyword.length(); - str.insert(pos,color2); - pos+= color2.length(); - } -} - -std::string DialogueWindow::parseText(const std::string& text) -{ - bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) - - std::vector topics; - - bool hasSeparator = false; - for (unsigned int i=0; igetItemCount(); ++i) - { - if (mTopicsList->getItemNameAt(i) == "") - hasSeparator = true; - } - - for(unsigned int i = 0;igetItemCount();i++) - { - std::string keyWord = mTopicsList->getItemNameAt(i); - if (separatorReached || !hasSeparator) - topics.push_back(keyWord); - else if (keyWord == "") - separatorReached = true; - } - - // sort by length to make sure longer topics are replaced first - std::sort(topics.begin(), topics.end(), sortByLength); - - std::vector hypertext = MWDialogue::ParseHyperText(text); - - size_t historySize = 0; - if(mHistory->getClient()->getSubWidgetText() != NULL) - { - historySize = mHistory->getOnlyText().size(); - } - - std::string result; - size_t hypertextPos = 0; - for (size_t i = 0; i < hypertext.size(); ++i) - { - if (hypertext[i].mLink) + for(unsigned int i = 0;igetItemCount();i++) { - size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); - std::string standardForm = hypertext[i].mText; - for(; asterisk_count > 0; --asterisk_count) - standardForm.append("*"); + std::string keyWord = mTopicsList->getItemNameAt(i); + if (separatorReached || !hasSeparator) + topics.push_back(keyWord); + else if (keyWord == "") + separatorReached = true; + } - standardForm = - MWBase::Environment::get().getWindowManager()-> - getTranslationDataStorage().topicStandardForm(standardForm); + // sort by length to make sure longer topics are replaced first + std::sort(topics.begin(), topics.end(), sortByLength); - if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() ) + std::vector hypertext = MWDialogue::ParseHyperText(text); + + size_t historySize = 0; + if(mHistory->getClient()->getSubWidgetText() != NULL) + { + historySize = mHistory->getOnlyText().size(); + } + + std::string result; + size_t hypertextPos = 0; + for (size_t i = 0; i < hypertext.size(); ++i) + { + if (hypertext[i].mLink) { - result.append("#686EBA").append(hypertext[i].mText).append("#B29154"); + size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); + std::string standardForm = hypertext[i].mText; + for(; asterisk_count > 0; --asterisk_count) + standardForm.append("*"); - mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length(); - mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm); + standardForm = + MWBase::Environment::get().getWindowManager()-> + getTranslationDataStorage().topicStandardForm(standardForm); + + if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() ) + { + result.append("#686EBA").append(hypertext[i].mText).append("#B29154"); + + mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length(); + mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm); + } + else + result += hypertext[i].mText; } else - result += hypertext[i].mText; - } - else - { - if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { - for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { - addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154"); + for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + { + addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154"); + } } + + result += hypertext[i].mText; } - result += hypertext[i].mText; + hypertextPos += MyGUI::UString(hypertext[i].mText).length(); } - hypertextPos += MyGUI::UString(hypertext[i].mText).length(); + return result; } - return result; -} - -void DialogueWindow::addText(std::string text) -{ - mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); -} - -void DialogueWindow::addMessageBox(const std::string& text) -{ - mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); -} - -void DialogueWindow::addTitle(std::string text) -{ - // This is called from the dialogue manager, so text is - // case-smashed - thus we have to retrieve the correct case - // of the text through the topic list. - for (size_t i=0; igetItemCount(); ++i) + void DialogueWindow::addText(std::string text) { - std::string item = mTopicsList->getItemNameAt(i); - if (lower_string(item) == text) - text = item; + mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); } - mHistory->addDialogHeading(text); -} - -void DialogueWindow::askQuestion(std::string question) -{ - mHistory->addDialogText("#572D21"+question+"#B29154"+" "); -} - -void DialogueWindow::updateOptions() -{ - //Clear the list of topics - mTopicsList->clear(); - mHyperLinks.clear(); - mHistory->eraseText(0, mHistory->getTextLength()); - - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + void DialogueWindow::addMessageBox(const std::string& text) { - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); - mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); } -} -void DialogueWindow::goodbye() -{ - mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); - mTopicsList->setEnabled(false); - mEnabled = false; -} - -void DialogueWindow::onReferenceUnavailable() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); -} - -void DialogueWindow::onFrame() -{ - if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + void DialogueWindow::addTitle(std::string text) { - int disp = std::max(0, std::min(100, - MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) - + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(disp); - mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); + // This is called from the dialogue manager, so text is + // case-smashed - thus we have to retrieve the correct case + // of the text through the topic list. + for (size_t i=0; igetItemCount(); ++i) + { + std::string item = mTopicsList->getItemNameAt(i); + if (lower_string(item) == text) + text = item; + } + + mHistory->addDialogHeading(text); + } + + void DialogueWindow::askQuestion(std::string question) + { + mHistory->addDialogText("#572D21"+question+"#B29154"+" "); + } + + void DialogueWindow::updateOptions() + { + //Clear the list of topics + mTopicsList->clear(); + mHyperLinks.clear(); + mHistory->eraseText(0, mHistory->getTextLength()); + + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + } + } + + void DialogueWindow::goodbye() + { + mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); + mTopicsList->setEnabled(false); + mEnabled = false; + } + + void DialogueWindow::onReferenceUnavailable() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + } + + void DialogueWindow::onFrame() + { + if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + int disp = std::max(0, std::min(100, + MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(disp); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); + } } } diff --git a/apps/openmw/mwgui/dialoguehistory.cpp b/apps/openmw/mwgui/dialoguehistory.cpp index a122a78916..d99d55bc12 100644 --- a/apps/openmw/mwgui/dialoguehistory.cpp +++ b/apps/openmw/mwgui/dialoguehistory.cpp @@ -12,65 +12,67 @@ #include #include -using namespace MWGui; -using namespace Widgets; - -MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) +namespace MWGui { - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::TextIterator iterator(getCaption()); - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if (pos < _pos) - continue; - else if (pos == _pos) - break; - } - return colour; -} -MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) -{ - bool breakOnNext = false; - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::UString colour2 = colour; - MyGUI::TextIterator iterator(getCaption()); - MyGUI::TextIterator col_start = iterator; - while(iterator.moveNext()) + MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if(colour != colour2) + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::TextIterator iterator(getCaption()); + while(iterator.moveNext()) { - if(breakOnNext) + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if (pos < _pos) + continue; + else if (pos == _pos) + break; + } + return colour; + } + + MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) + { + bool breakOnNext = false; + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::UString colour2 = colour; + MyGUI::TextIterator iterator(getCaption()); + MyGUI::TextIterator col_start = iterator; + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if(colour != colour2) { - return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + if(breakOnNext) + { + return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + } + col_start = iterator; + colour2 = colour; + } + if (pos < _pos) + continue; + else if (pos == _pos) + { + breakOnNext = true; } - col_start = iterator; - colour2 = colour; - } - if (pos < _pos) - continue; - else if (pos == _pos) - { - breakOnNext = true; } + return ""; } - return ""; -} -void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) -{ - MyGUI::UString head("\n#D8C09A"); - head.append(parText); - head.append("#B29154\n"); - addText(head); -} + void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) + { + MyGUI::UString head("\n#D8C09A"); + head.append(parText); + head.append("#B29154\n"); + addText(head); + } + + void DialogueHistory::addDialogText(const MyGUI::UString& parText) + { + addText(parText); + addText("\n"); + } -void DialogueHistory::addDialogText(const MyGUI::UString& parText) -{ - addText(parText); - addText("\n"); } diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index b21b903bde..2d72f21740 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -9,8 +9,6 @@ #include #include -using namespace MWGui; - namespace { int convertFromHex(std::string hex) @@ -78,287 +76,292 @@ namespace } } -std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) +namespace MWGui { - using Ogre::UTFString; - std::vector result; - MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); - - boost::algorithm::replace_all(utf8Text, "\n", ""); - boost::algorithm::replace_all(utf8Text, "
", "\n"); - boost::algorithm::replace_all(utf8Text, "

", "\n\n"); - - UTFString text(utf8Text); - const int spacing = 48; - - const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); - const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); - const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); - - while (!text.empty()) + std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) { - // read in characters until we have exceeded the size, or run out of text - int currentWidth = 0; - int currentHeight = 0; + using Ogre::UTFString; + std::vector result; - size_t currentWordStart = 0; - size_t index = 0; - while (currentHeight <= height - spacing && index < text.size()) + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); + + boost::algorithm::replace_all(utf8Text, "\n", ""); + boost::algorithm::replace_all(utf8Text, "
", "\n"); + boost::algorithm::replace_all(utf8Text, "

", "\n\n"); + + UTFString text(utf8Text); + const int spacing = 48; + + const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); + const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); + const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); + + while (!text.empty()) { - const UTFString::unicode_char ch = text.getChar(index); - if (ch == LEFT_ANGLE) - { - const size_t tagStart = index + 1; - const size_t tagEnd = text.find('>', tagStart); - if (tagEnd == UTFString::npos) - throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); + // read in characters until we have exceeded the size, or run out of text + int currentWidth = 0; + int currentHeight = 0; - if (boost::algorithm::starts_with(tag, "IMG")) + size_t currentWordStart = 0; + size_t index = 0; + while (currentHeight <= height - spacing && index < text.size()) + { + const UTFString::unicode_char ch = text.getChar(index); + if (ch == LEFT_ANGLE) { - const int h = mHeight; - parseImage(tag, false); - currentHeight += (mHeight - h); - currentWidth = 0; - } - else if (boost::algorithm::starts_with(tag, "FONT")) - { - parseFont(tag); - if (currentWidth != 0) { - currentHeight += currentFontHeight(); - currentWidth = 0; - } - currentWidth = 0; - } - else if (boost::algorithm::starts_with(tag, "DIV")) - { - parseDiv(tag); - if (currentWidth != 0) { - currentHeight += currentFontHeight(); - currentWidth = 0; - } - } - index = tagEnd; - } - else if (ch == NEWLINE) - { - currentHeight += currentFontHeight(); - currentWidth = 0; - currentWordStart = index; - } - else if (ch == SPACE) - { - currentWidth += 3; // keep this in sync with the font's SpaceWidth property - currentWordStart = index; - } - else - { - currentWidth += widthForCharGlyph(ch); - } - - if (currentWidth > width) - { - currentHeight += currentFontHeight(); - currentWidth = 0; - // add size of the current word - UTFString word = text.substr(currentWordStart, index - currentWordStart); - for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) - currentWidth += widthForCharGlyph(it.getCharacter()); - } - index += UTFString::_utf16_char_length(ch); - } - const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) - ? currentWordStart : index; - - result.push_back(text.substr(0, pageEnd).asUTF8()); - text.erase(0, pageEnd); - } - - return result; -} - -float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const -{ - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); - return MyGUI::FontManager::getInstance().getByName(fontName) - ->getGlyphInfo(unicodeChar)->width; -} - -float BookTextParser::currentFontHeight() const -{ - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); - return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); -} - -MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) -{ - MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - text = Interpreter::fixDefinesBook(text, interpreterContext); - - mParent = parent; - mWidth = width; - mHeight = 0; - - assert(mParent); - while (mParent->getChildCount()) - { - MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); - } - - boost::algorithm::replace_all(text, "\n", ""); - boost::algorithm::replace_all(text, "
", "\n"); - boost::algorithm::replace_all(text, "

", "\n\n"); - - // remove leading newlines -// while (text[0] == '\n') -// text.erase(0); - - // remove trailing " - if (text[text.size()-1] == '\"') - text.erase(text.size()-1); - - parseSubText(text); - return MyGUI::IntSize(mWidth, mHeight); -} - -void BookTextParser::parseImage(std::string tag, bool createWidget) -{ - int src_start = tag.find("SRC=")+5; - std::string image = tag.substr(src_start, tag.find('"', src_start)-src_start); - - // fix texture extension to .dds - if (image.size() > 4) - { - image[image.size()-3] = 'd'; - image[image.size()-2] = 'd'; - image[image.size()-1] = 's'; - } - - int width_start = tag.find("WIDTH=")+7; - int width = boost::lexical_cast(tag.substr(width_start, tag.find('"', width_start)-width_start)); - - int height_start = tag.find("HEIGHT=")+8; - int height = boost::lexical_cast(tag.substr(height_start, tag.find('"', height_start)-height_start)); - - if (createWidget) - { - MyGUI::ImageBox* box = mParent->createWidget ("ImageBox", - MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top, - mParent->getName() + boost::lexical_cast(mParent->getChildCount())); - box->setImageTexture("bookart\\" + image); - box->setProperty("NeedMouse", "false"); - } - - mWidth = std::max(mWidth, width); - mHeight += height; -} - -void BookTextParser::parseDiv(std::string tag) -{ - if (tag.find("ALIGN=") == std::string::npos) - return; - - int align_start = tag.find("ALIGN=")+7; - std::string align = tag.substr(align_start, tag.find('"', align_start)-align_start); - if (align == "CENTER") - mTextStyle.mTextAlign = MyGUI::Align::HCenter; - else if (align == "LEFT") - mTextStyle.mTextAlign = MyGUI::Align::Left; -} - -void BookTextParser::parseFont(std::string tag) -{ - if (tag.find("COLOR=") != std::string::npos) - { - int color_start = tag.find("COLOR=")+7; - std::string color = tag.substr(color_start, tag.find('"', color_start)-color_start); - - mTextStyle.mColour = MyGUI::Colour( - convertFromHex(color.substr(0, 2))/255.0, - convertFromHex(color.substr(2, 2))/255.0, - convertFromHex(color.substr(4, 2))/255.0); - } - if (tag.find("FACE=") != std::string::npos) - { - int face_start = tag.find("FACE=")+6; - std::string face = tag.substr(face_start, tag.find('"', face_start)-face_start); - - if (face != "Magic Cards") - mTextStyle.mFont = face; - } - if (tag.find("SIZE=") != std::string::npos) - { - /// \todo - } -} - -void BookTextParser::parseSubText(std::string text) -{ - if (text[0] == '<') - { - const size_t tagStart = 1; - const size_t tagEnd = text.find('>', tagStart); - if (tagEnd == std::string::npos) - throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - const std::string tag = text.substr(tagStart, tagEnd - tagStart); - - if (boost::algorithm::starts_with(tag, "IMG")) - parseImage(tag); - if (boost::algorithm::starts_with(tag, "FONT")) - parseFont(tag); - if (boost::algorithm::starts_with(tag, "DOV")) - parseDiv(tag); - - text.erase(0, tagEnd + 1); - } - - size_t tagStart = std::string::npos; - std::string realText; // real text, without tags - for (size_t i = 0; i= text.size()) + const size_t tagStart = index + 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == UTFString::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - ++i; - c = text[i]; + const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); + + if (boost::algorithm::starts_with(tag, "IMG")) + { + const int h = mHeight; + parseImage(tag, false); + currentHeight += (mHeight - h); + currentWidth = 0; + } + else if (boost::algorithm::starts_with(tag, "FONT")) + { + parseFont(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } + currentWidth = 0; + } + else if (boost::algorithm::starts_with(tag, "DIV")) + { + parseDiv(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } + } + index = tagEnd; + } + else if (ch == NEWLINE) + { + currentHeight += currentFontHeight(); + currentWidth = 0; + currentWordStart = index; + } + else if (ch == SPACE) + { + currentWidth += 3; // keep this in sync with the font's SpaceWidth property + currentWordStart = index; + } + else + { + currentWidth += widthForCharGlyph(ch); + } + + if (currentWidth > width) + { + currentHeight += currentFontHeight(); + currentWidth = 0; + // add size of the current word + UTFString word = text.substr(currentWordStart, index - currentWordStart); + for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) + currentWidth += widthForCharGlyph(it.getCharacter()); + } + index += UTFString::_utf16_char_length(ch); + } + const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) + ? currentWordStart : index; + + result.push_back(text.substr(0, pageEnd).asUTF8()); + text.erase(0, pageEnd); + } + + return result; + } + + float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const + { + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName) + ->getGlyphInfo(unicodeChar)->width; + } + + float BookTextParser::currentFontHeight() const + { + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); + } + + MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) + { + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesBook(text, interpreterContext); + + mParent = parent; + mWidth = width; + mHeight = 0; + + assert(mParent); + while (mParent->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); + } + + boost::algorithm::replace_all(text, "\n", ""); + boost::algorithm::replace_all(text, "
", "\n"); + boost::algorithm::replace_all(text, "

", "\n\n"); + + // remove leading newlines + // while (text[0] == '\n') + // text.erase(0); + + // remove trailing " + if (text[text.size()-1] == '\"') + text.erase(text.size()-1); + + parseSubText(text); + return MyGUI::IntSize(mWidth, mHeight); + } + + void BookTextParser::parseImage(std::string tag, bool createWidget) + { + int src_start = tag.find("SRC=")+5; + std::string image = tag.substr(src_start, tag.find('"', src_start)-src_start); + + // fix texture extension to .dds + if (image.size() > 4) + { + image[image.size()-3] = 'd'; + image[image.size()-2] = 'd'; + image[image.size()-1] = 's'; + } + + int width_start = tag.find("WIDTH=")+7; + int width = boost::lexical_cast(tag.substr(width_start, tag.find('"', width_start)-width_start)); + + int height_start = tag.find("HEIGHT=")+8; + int height = boost::lexical_cast(tag.substr(height_start, tag.find('"', height_start)-height_start)); + + if (createWidget) + { + MyGUI::ImageBox* box = mParent->createWidget ("ImageBox", + MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top, + mParent->getName() + boost::lexical_cast(mParent->getChildCount())); + box->setImageTexture("bookart\\" + image); + box->setProperty("NeedMouse", "false"); + } + + mWidth = std::max(mWidth, width); + mHeight += height; + } + + void BookTextParser::parseDiv(std::string tag) + { + if (tag.find("ALIGN=") == std::string::npos) + return; + + int align_start = tag.find("ALIGN=")+7; + std::string align = tag.substr(align_start, tag.find('"', align_start)-align_start); + if (align == "CENTER") + mTextStyle.mTextAlign = MyGUI::Align::HCenter; + else if (align == "LEFT") + mTextStyle.mTextAlign = MyGUI::Align::Left; + } + + void BookTextParser::parseFont(std::string tag) + { + if (tag.find("COLOR=") != std::string::npos) + { + int color_start = tag.find("COLOR=")+7; + std::string color = tag.substr(color_start, tag.find('"', color_start)-color_start); + + mTextStyle.mColour = MyGUI::Colour( + convertFromHex(color.substr(0, 2))/255.0, + convertFromHex(color.substr(2, 2))/255.0, + convertFromHex(color.substr(4, 2))/255.0); + } + if (tag.find("FACE=") != std::string::npos) + { + int face_start = tag.find("FACE=")+6; + std::string face = tag.substr(face_start, tag.find('"', face_start)-face_start); + + if (face != "Magic Cards") + mTextStyle.mFont = face; + } + if (tag.find("SIZE=") != std::string::npos) + { + /// \todo + } + } + + void BookTextParser::parseSubText(std::string text) + { + if (text[0] == '<') + { + const size_t tagStart = 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == std::string::npos) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart); + + if (boost::algorithm::starts_with(tag, "IMG")) + parseImage(tag); + if (boost::algorithm::starts_with(tag, "FONT")) + parseFont(tag); + if (boost::algorithm::starts_with(tag, "DOV")) + parseDiv(tag); + + text.erase(0, tagEnd + 1); + } + + size_t tagStart = std::string::npos; + std::string realText; // real text, without tags + for (size_t i = 0; i= text.size()) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + ++i; + c = text[i]; + } + continue; + } + else + { + tagStart = i; + break; } - continue; } else - { - tagStart = i; - break; - } + realText += c; + } + + MyGUI::EditBox* box = mParent->createWidget("NormalText", + MyGUI::IntCoord(0, mHeight, mWidth, 24), MyGUI::Align::Left | MyGUI::Align::Top, + mParent->getName() + boost::lexical_cast(mParent->getChildCount())); + box->setProperty("Static", "true"); + box->setProperty("MultiLine", "true"); + box->setProperty("WordWrap", "true"); + box->setProperty("NeedMouse", "false"); + box->setMaxTextLength(realText.size()); + box->setTextAlign(mTextStyle.mTextAlign); + box->setTextColour(mTextStyle.mColour); + box->setFontName(mTextStyle.mFont); + box->setCaption(realText); + box->setSize(box->getSize().width, box->getTextSize().height); + mHeight += box->getTextSize().height; + + if (tagStart != std::string::npos) + { + parseSubText(text.substr(tagStart, text.size())); } - else - realText += c; } - MyGUI::EditBox* box = mParent->createWidget("NormalText", - MyGUI::IntCoord(0, mHeight, mWidth, 24), MyGUI::Align::Left | MyGUI::Align::Top, - mParent->getName() + boost::lexical_cast(mParent->getChildCount())); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - box->setProperty("WordWrap", "true"); - box->setProperty("NeedMouse", "false"); - box->setMaxTextLength(realText.size()); - box->setTextAlign(mTextStyle.mTextAlign); - box->setTextColour(mTextStyle.mColour); - box->setFontName(mTextStyle.mFont); - box->setCaption(realText); - box->setSize(box->getSize().width, box->getTextSize().height); - mHeight += box->getTextSize().height; - - if (tagStart != std::string::npos) - { - parseSubText(text.substr(tagStart, text.size())); - } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 988bcfc241..59e00bf69d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -12,528 +12,531 @@ #include "console.hpp" #include "spellicons.hpp" -using namespace MWGui; - -HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) - : Layout("openmw_hud.layout") - , mHealth(NULL) - , mMagicka(NULL) - , mStamina(NULL) - , mWeapImage(NULL) - , mSpellImage(NULL) - , mWeapStatus(NULL) - , mSpellStatus(NULL) - , mEffectBox(NULL) - , mMinimap(NULL) - , mCompass(NULL) - , mCrosshair(NULL) - , mFpsBox(NULL) - , mFpsCounter(NULL) - , mTriangleCounter(NULL) - , mBatchCounter(NULL) - , mHealthManaStaminaBaseLeft(0) - , mWeapBoxBaseLeft(0) - , mSpellBoxBaseLeft(0) - , mEffectBoxBaseRight(0) - , mMinimapBoxBaseRight(0) - , mDragAndDrop(dragAndDrop) - , mCellNameTimer(0.0f) - , mCellNameBox(NULL) - , mMapVisible(true) - , mWeaponVisible(true) - , mSpellVisible(true) - , mWorldMouseOver(false) +namespace MWGui { - setCoord(0,0, width, height); - // Energy bars - getWidget(mHealthFrame, "HealthFrame"); - getWidget(mHealth, "Health"); - getWidget(mMagicka, "Magicka"); - getWidget(mStamina, "Stamina"); - mHealthManaStaminaBaseLeft = mHealthFrame->getLeft(); - - MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame; - getWidget(healthFrame, "HealthFrame"); - getWidget(magickaFrame, "MagickaFrame"); - getWidget(fatigueFrame, "FatigueFrame"); - healthFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); - magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); - fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); - - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - - // Item and spell images and status bars - getWidget(mWeapBox, "WeapBox"); - getWidget(mWeapImage, "WeapImage"); - getWidget(mWeapStatus, "WeapStatus"); - mWeapBoxBaseLeft = mWeapBox->getLeft(); - mWeapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); - - getWidget(mSpellBox, "SpellBox"); - getWidget(mSpellImage, "SpellImage"); - getWidget(mSpellStatus, "SpellStatus"); - mSpellBoxBaseLeft = mSpellBox->getLeft(); - mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); - - getWidget(mEffectBox, "EffectBox"); - mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); - - getWidget(mMinimapBox, "MiniMapBox"); - mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); - getWidget(mMinimap, "MiniMap"); - getWidget(mCompass, "Compass"); - getWidget(mMinimapButton, "MiniMapButton"); - mMinimapButton->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); - - getWidget(mCellNameBox, "CellName"); - getWidget(mWeaponSpellBox, "WeaponSpellName"); - - getWidget(mCrosshair, "Crosshair"); - - setFpsLevel(fpsLevel); - - getWidget(mTriangleCounter, "TriangleCounter"); - getWidget(mBatchCounter, "BatchCounter"); - - LocalMapBase::init(mMinimap, mCompass, this); - - mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); - mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); - mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); - - mSpellIcons = new SpellIcons(); -} - -HUD::~HUD() -{ - delete mSpellIcons; -} - -void HUD::setFpsLevel(int level) -{ - mFpsCounter = 0; - - MyGUI::Widget* fps; - getWidget(fps, "FPSBoxAdv"); - fps->setVisible(false); - getWidget(fps, "FPSBox"); - fps->setVisible(false); - - if (level == 2) + HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) + : Layout("openmw_hud.layout") + , mHealth(NULL) + , mMagicka(NULL) + , mStamina(NULL) + , mWeapImage(NULL) + , mSpellImage(NULL) + , mWeapStatus(NULL) + , mSpellStatus(NULL) + , mEffectBox(NULL) + , mMinimap(NULL) + , mCompass(NULL) + , mCrosshair(NULL) + , mFpsBox(NULL) + , mFpsCounter(NULL) + , mTriangleCounter(NULL) + , mBatchCounter(NULL) + , mHealthManaStaminaBaseLeft(0) + , mWeapBoxBaseLeft(0) + , mSpellBoxBaseLeft(0) + , mEffectBoxBaseRight(0) + , mMinimapBoxBaseRight(0) + , mDragAndDrop(dragAndDrop) + , mCellNameTimer(0.0f) + , mCellNameBox(NULL) + , mMapVisible(true) + , mWeaponVisible(true) + , mSpellVisible(true) + , mWorldMouseOver(false) { - getWidget(mFpsBox, "FPSBoxAdv"); - mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounterAdv"); + setCoord(0,0, width, height); + + // Energy bars + getWidget(mHealthFrame, "HealthFrame"); + getWidget(mHealth, "Health"); + getWidget(mMagicka, "Magicka"); + getWidget(mStamina, "Stamina"); + mHealthManaStaminaBaseLeft = mHealthFrame->getLeft(); + + MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame; + getWidget(healthFrame, "HealthFrame"); + getWidget(magickaFrame, "MagickaFrame"); + getWidget(fatigueFrame, "FatigueFrame"); + healthFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // Item and spell images and status bars + getWidget(mWeapBox, "WeapBox"); + getWidget(mWeapImage, "WeapImage"); + getWidget(mWeapStatus, "WeapStatus"); + mWeapBoxBaseLeft = mWeapBox->getLeft(); + mWeapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); + + getWidget(mSpellBox, "SpellBox"); + getWidget(mSpellImage, "SpellImage"); + getWidget(mSpellStatus, "SpellStatus"); + mSpellBoxBaseLeft = mSpellBox->getLeft(); + mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); + + getWidget(mEffectBox, "EffectBox"); + mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); + + getWidget(mMinimapBox, "MiniMapBox"); + mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); + getWidget(mMinimap, "MiniMap"); + getWidget(mCompass, "Compass"); + getWidget(mMinimapButton, "MiniMapButton"); + mMinimapButton->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + + getWidget(mCellNameBox, "CellName"); + getWidget(mWeaponSpellBox, "WeaponSpellName"); + + getWidget(mCrosshair, "Crosshair"); + + setFpsLevel(fpsLevel); + + getWidget(mTriangleCounter, "TriangleCounter"); + getWidget(mBatchCounter, "BatchCounter"); + + LocalMapBase::init(mMinimap, mCompass, this); + + mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); + mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); + mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); + + mSpellIcons = new SpellIcons(); } - else if (level == 1) + + HUD::~HUD() { - getWidget(mFpsBox, "FPSBox"); - mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounter"); + delete mSpellIcons; } -} -void HUD::setFPS(float fps) -{ - if (mFpsCounter) - mFpsCounter->setCaption(boost::lexical_cast((int)fps)); -} - -void HUD::setTriangleCount(unsigned int count) -{ - mTriangleCounter->setCaption(boost::lexical_cast(count)); -} - -void HUD::setBatchCount(unsigned int count) -{ - mBatchCounter->setCaption(boost::lexical_cast(count)); -} - -void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = + void HUD::setFpsLevel(int level) { - "HBar", "MBar", "FBar", 0 - }; + mFpsCounter = 0; - for (int i=0; ids[i]; ++i) - if (ids[i]==id) + MyGUI::Widget* fps; + getWidget(fps, "FPSBoxAdv"); + fps->setVisible(false); + getWidget(fps, "FPSBox"); + fps->setVisible(false); + + if (level == 2) { - MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - switch (i) - { - case 0: - mHealth->setProgressRange (value.getModified()); - mHealth->setProgressPosition (value.getCurrent()); - getWidget(w, "HealthFrame"); - w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); - break; - case 1: - mMagicka->setProgressRange (value.getModified()); - mMagicka->setProgressPosition (value.getCurrent()); - getWidget(w, "MagickaFrame"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); - break; - case 2: - mStamina->setProgressRange (value.getModified()); - mStamina->setProgressPosition (value.getCurrent()); - getWidget(w, "FatigueFrame"); - w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); - break; - } + getWidget(mFpsBox, "FPSBoxAdv"); + mFpsBox->setVisible(true); + getWidget(mFpsCounter, "FPSCounterAdv"); + } + else if (level == 1) + { + getWidget(mFpsBox, "FPSBox"); + mFpsBox->setVisible(true); + getWidget(mFpsCounter, "FPSCounter"); } -} - -void HUD::onWorldClicked(MyGUI::Widget* _sender) -{ - if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ()) - return; - - if (mDragAndDrop->mIsOnDragAndDrop) - { - // drop item into the gameworld - MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - - MWBase::World* world = MWBase::Environment::get().getWorld(); - - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); - float mouseX = cursorPosition.left / float(viewSize.width); - float mouseY = cursorPosition.top / float(viewSize.height); - - int origCount = object.getRefData().getCount(); - object.getRefData().setCount(mDragAndDrop->mDraggedCount); - - if (world->canPlaceObject(mouseX, mouseY)) - world->placeObject(object, mouseX, mouseY); - else - world->dropObjectOnGround(world->getPlayer().getPlayer(), object); - - MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - - std::string sound = MWWorld::Class::get(object).getDownSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - // remove object from the container it was coming from - object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); - - mDragAndDrop->mIsOnDragAndDrop = false; - MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget = 0; - - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - mDragAndDrop->mDraggedFrom->drawItems(); - mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); } - else - { - GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) ) + void HUD::setFPS(float fps) + { + if (mFpsCounter) + mFpsCounter->setCaption(boost::lexical_cast((int)fps)); + } + + void HUD::setTriangleCount(unsigned int count) + { + mTriangleCounter->setCaption(boost::lexical_cast(count)); + } + + void HUD::setBatchCount(unsigned int count) + { + mBatchCounter->setCaption(boost::lexical_cast(count)); + } + + void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) + { + static const char *ids[] = + { + "HBar", "MBar", "FBar", 0 + }; + + for (int i=0; ids[i]; ++i) + if (ids[i]==id) + { + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + switch (i) + { + case 0: + mHealth->setProgressRange (value.getModified()); + mHealth->setProgressPosition (value.getCurrent()); + getWidget(w, "HealthFrame"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + break; + case 1: + mMagicka->setProgressRange (value.getModified()); + mMagicka->setProgressPosition (value.getCurrent()); + getWidget(w, "MagickaFrame"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + break; + case 2: + mStamina->setProgressRange (value.getModified()); + mStamina->setProgressPosition (value.getCurrent()); + getWidget(w, "FatigueFrame"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + break; + } + } + } + + void HUD::onWorldClicked(MyGUI::Widget* _sender) + { + if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ()) return; - MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); - - if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); - else if ((mode == GM_Container) || (mode == GM_Inventory)) + if (mDragAndDrop->mIsOnDragAndDrop) { - // pick up object - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object); - } - } -} + // drop item into the gameworld + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); -void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) -{ - if (mDragAndDrop->mIsOnDragAndDrop) - { - mWorldMouseOver = false; + MWBase::World* world = MWBase::Environment::get().getWorld(); - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); - float mouseX = cursorPosition.left / float(viewSize.width); - float mouseY = cursorPosition.top / float(viewSize.height); + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); - MWBase::World* world = MWBase::Environment::get().getWorld(); + int origCount = object.getRefData().getCount(); + object.getRefData().setCount(mDragAndDrop->mDraggedCount); - // if we can't drop the object at the wanted position, show the "drop on ground" cursor. - bool canDrop = world->canPlaceObject(mouseX, mouseY); + if (world->canPlaceObject(mouseX, mouseY)) + world->placeObject(object, mouseX, mouseY); + else + world->dropObjectOnGround(world->getPlayer().getPlayer(), object); - if (!canDrop) - MWBase::Environment::get().getWindowManager()->changePointer("drop_ground"); - else MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + // remove object from the container it was coming from + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget = 0; + + MWBase::Environment::get().getWindowManager()->setDragDrop(false); + mDragAndDrop->mDraggedFrom->drawItems(); + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); + } + else + { + GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + + if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) ) + return; + + MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); + + if (mode == GM_Console) + MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); + else if ((mode == GM_Container) || (mode == GM_Inventory)) + { + // pick up object + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object); + } + } } - else + + void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) + { + if (mDragAndDrop->mIsOnDragAndDrop) + { + mWorldMouseOver = false; + + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); + + MWBase::World* world = MWBase::Environment::get().getWorld(); + + // if we can't drop the object at the wanted position, show the "drop on ground" cursor. + bool canDrop = world->canPlaceObject(mouseX, mouseY); + + if (!canDrop) + MWBase::Environment::get().getWindowManager()->changePointer("drop_ground"); + else + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + + } + else + { + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + mWorldMouseOver = true; + } + } + + void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) { MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - mWorldMouseOver = true; - } -} - -void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) -{ - MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - mWorldMouseOver = false; -} - -void HUD::onHMSClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats); -} - -void HUD::onMapClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); -} - -void HUD::onWeaponClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory); -} - -void HUD::onMagicClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); -} - -void HUD::setCellName(const std::string& cellName) -{ - if (mCellName != cellName) - { - mCellNameTimer = 5.0f; - mCellName = cellName; - - mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}"); - mCellNameBox->setVisible(mMapVisible); - } -} - -void HUD::onFrame(float dt) -{ - mCellNameTimer -= dt; - mWeaponSpellTimer -= dt; - if (mCellNameTimer < 0) - mCellNameBox->setVisible(false); - if (mWeaponSpellTimer < 0) - mWeaponSpellBox->setVisible(false); -} - -void HUD::onResChange(int width, int height) -{ - setCoord(0, 0, width, height); -} - -void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) -{ - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - std::string spellName = spell->mName; - if (spellName != mSpellName && mSpellVisible) - { - mWeaponSpellTimer = 5.0f; - mSpellName = spellName; - mWeaponSpellBox->setCaption(mSpellName); - mWeaponSpellBox->setVisible(true); + mWorldMouseOver = false; } - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(successChancePercent); - - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - - mSpellBox->setUserString("ToolTipType", "Spell"); - mSpellBox->setUserString("Spell", spellId); - - // use the icon of the first effect - const ESM::MagicEffect* effect = - MWBase::Environment::get().getWorld()->getStore().get().find(spell->mEffects.mList.front().mEffectID); - - std::string icon = effect->mIcon; - int slashPos = icon.find("\\"); - icon.insert(slashPos+1, "b_"); - icon = std::string("icons\\") + icon; - Widgets::fixTexturePath(icon); - mSpellImage->setImageTexture(icon); -} - -void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) -{ - std::string itemName = MWWorld::Class::get(item).getName(item); - if (itemName != mSpellName && mSpellVisible) + void HUD::onHMSClicked(MyGUI::Widget* _sender) { - mWeaponSpellTimer = 5.0f; - mSpellName = itemName; - mWeaponSpellBox->setCaption(mSpellName); - mWeaponSpellBox->setVisible(true); + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats); } - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(chargePercent); - - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - - mSpellBox->setUserString("ToolTipType", "ItemPtr"); - mSpellBox->setUserData(item); - - mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = mSpellImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) - , MyGUI::Align::Stretch); - - std::string path = std::string("icons\\"); - path+=MWWorld::Class::get(item).getInventoryIcon(item); - Widgets::fixTexturePath(path); - itemBox->setImageTexture(path); - itemBox->setNeedMouseFocus(false); -} - -void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) -{ - std::string itemName = MWWorld::Class::get(item).getName(item); - if (itemName != mWeaponName && mWeaponVisible) + void HUD::onMapClicked(MyGUI::Widget* _sender) { - mWeaponSpellTimer = 5.0f; - mWeaponName = itemName; - mWeaponSpellBox->setCaption(mWeaponName); - mWeaponSpellBox->setVisible(true); + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); } - mWeapBox->setUserString("ToolTipType", "ItemPtr"); - mWeapBox->setUserData(item); - - mWeapStatus->setProgressRange(100); - mWeapStatus->setProgressPosition(durabilityPercent); - - if (mWeapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); - - std::string path = std::string("icons\\"); - path+=MWWorld::Class::get(item).getInventoryIcon(item); - Widgets::fixTexturePath(path); - - if (MWWorld::Class::get(item).getEnchantment(item) != "") + void HUD::onWeaponClicked(MyGUI::Widget* _sender) { - mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory); + } + + void HUD::onMagicClicked(MyGUI::Widget* _sender) + { + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); + } + + void HUD::setCellName(const std::string& cellName) + { + if (mCellName != cellName) + { + mCellNameTimer = 5.0f; + mCellName = cellName; + + mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}"); + mCellNameBox->setVisible(mMapVisible); + } + } + + void HUD::onFrame(float dt) + { + mCellNameTimer -= dt; + mWeaponSpellTimer -= dt; + if (mCellNameTimer < 0) + mCellNameBox->setVisible(false); + if (mWeaponSpellTimer < 0) + mWeaponSpellBox->setVisible(false); + } + + void HUD::onResChange(int width, int height) + { + setCoord(0, 0, width, height); + } + + void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) + { + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + std::string spellName = spell->mName; + if (spellName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = spellName; + mWeaponSpellBox->setCaption(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(successChancePercent); + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + + mSpellBox->setUserString("ToolTipType", "Spell"); + mSpellBox->setUserString("Spell", spellId); + + // use the icon of the first effect + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld()->getStore().get().find(spell->mEffects.mList.front().mEffectID); + + std::string icon = effect->mIcon; + int slashPos = icon.find("\\"); + icon.insert(slashPos+1, "b_"); + icon = std::string("icons\\") + icon; + Widgets::fixTexturePath(icon); + mSpellImage->setImageTexture(icon); + } + + void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) + { + std::string itemName = MWWorld::Class::get(item).getName(item); + if (itemName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = itemName; + mWeaponSpellBox->setCaption(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(chargePercent); + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + + mSpellBox->setUserString("ToolTipType", "ItemPtr"); + mSpellBox->setUserData(item); + + mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = mSpellImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) , MyGUI::Align::Stretch); + + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(item).getInventoryIcon(item); + Widgets::fixTexturePath(path); itemBox->setImageTexture(path); itemBox->setNeedMouseFocus(false); } - else - mWeapImage->setImageTexture(path); -} -void HUD::unsetSelectedSpell() -{ - std::string spellName = "#{sNone}"; - if (spellName != mSpellName && mSpellVisible) + void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) { - mWeaponSpellTimer = 5.0f; - mSpellName = spellName; - mWeaponSpellBox->setCaptionWithReplacing(mSpellName); - mWeaponSpellBox->setVisible(true); + std::string itemName = MWWorld::Class::get(item).getName(item); + if (itemName != mWeaponName && mWeaponVisible) + { + mWeaponSpellTimer = 5.0f; + mWeaponName = itemName; + mWeaponSpellBox->setCaption(mWeaponName); + mWeaponSpellBox->setVisible(true); + } + + mWeapBox->setUserString("ToolTipType", "ItemPtr"); + mWeapBox->setUserData(item); + + mWeapStatus->setProgressRange(100); + mWeapStatus->setProgressPosition(durabilityPercent); + + if (mWeapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); + + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(item).getInventoryIcon(item); + Widgets::fixTexturePath(path); + + if (MWWorld::Class::get(item).getEnchantment(item) != "") + { + mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + , MyGUI::Align::Stretch); + itemBox->setImageTexture(path); + itemBox->setNeedMouseFocus(false); + } + else + mWeapImage->setImageTexture(path); } - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(0); - mSpellImage->setImageTexture(""); - mSpellBox->clearUserStrings(); -} - -void HUD::unsetSelectedWeapon() -{ - std::string itemName = "#{sSkillHandtohand}"; - if (itemName != mWeaponName && mWeaponVisible) + void HUD::unsetSelectedSpell() { - mWeaponSpellTimer = 5.0f; - mWeaponName = itemName; - mWeaponSpellBox->setCaptionWithReplacing(mWeaponName); - mWeaponSpellBox->setVisible(true); + std::string spellName = "#{sNone}"; + if (spellName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = spellName; + mWeaponSpellBox->setCaptionWithReplacing(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(0); + mSpellImage->setImageTexture(""); + mSpellBox->clearUserStrings(); + } + + void HUD::unsetSelectedWeapon() + { + std::string itemName = "#{sSkillHandtohand}"; + if (itemName != mWeaponName && mWeaponVisible) + { + mWeaponSpellTimer = 5.0f; + mWeaponName = itemName; + mWeaponSpellBox->setCaptionWithReplacing(mWeaponName); + mWeaponSpellBox->setVisible(true); + } + + if (mWeapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); + mWeapStatus->setProgressRange(100); + mWeapStatus->setProgressPosition(0); + mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); + mWeapBox->clearUserStrings(); + } + + void HUD::setCrosshairVisible(bool visible) + { + mCrosshair->setVisible (visible); + } + + void HUD::setHmsVisible(bool visible) + { + mHealth->setVisible(visible); + mMagicka->setVisible(visible); + mStamina->setVisible(visible); + updatePositions(); + } + + void HUD::setWeapVisible(bool visible) + { + mWeapBox->setVisible(visible); + updatePositions(); + } + + void HUD::setSpellVisible(bool visible) + { + mSpellBox->setVisible(visible); + updatePositions(); + } + + void HUD::setEffectVisible(bool visible) + { + mEffectBox->setVisible (visible); + updatePositions(); + } + + void HUD::setMinimapVisible(bool visible) + { + mMinimapBox->setVisible (visible); + updatePositions(); + } + + void HUD::updatePositions() + { + int weapDx = 0, spellDx = 0; + if (!mHealth->getVisible()) + spellDx = weapDx = mWeapBoxBaseLeft - mHealthManaStaminaBaseLeft; + + if (!mWeapBox->getVisible()) + spellDx += mSpellBoxBaseLeft - mWeapBoxBaseLeft; + + mWeaponVisible = mWeapBox->getVisible(); + mSpellVisible = mSpellBox->getVisible(); + if (!mWeaponVisible && !mSpellVisible) + mWeaponSpellBox->setVisible(false); + + mWeapBox->setPosition(mWeapBoxBaseLeft - weapDx, mWeapBox->getTop()); + mSpellBox->setPosition(mSpellBoxBaseLeft - spellDx, mSpellBox->getTop()); + + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // effect box can have variable width -> variable left coordinate + int effectsDx = 0; + if (!mMinimapBox->getVisible ()) + effectsDx = (viewSize.width - mMinimapBoxBaseRight) - (viewSize.width - mEffectBoxBaseRight); + + mMapVisible = mMinimapBox->getVisible (); + mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); + } + + void HUD::update() + { + mSpellIcons->updateWidgets(mEffectBox, true); } - if (mWeapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); - mWeapStatus->setProgressRange(100); - mWeapStatus->setProgressPosition(0); - mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); - mWeapBox->clearUserStrings(); -} - -void HUD::setCrosshairVisible(bool visible) -{ - mCrosshair->setVisible (visible); -} - -void HUD::setHmsVisible(bool visible) -{ - mHealth->setVisible(visible); - mMagicka->setVisible(visible); - mStamina->setVisible(visible); - updatePositions(); -} - -void HUD::setWeapVisible(bool visible) -{ - mWeapBox->setVisible(visible); - updatePositions(); -} - -void HUD::setSpellVisible(bool visible) -{ - mSpellBox->setVisible(visible); - updatePositions(); -} - -void HUD::setEffectVisible(bool visible) -{ - mEffectBox->setVisible (visible); - updatePositions(); -} - -void HUD::setMinimapVisible(bool visible) -{ - mMinimapBox->setVisible (visible); - updatePositions(); -} - -void HUD::updatePositions() -{ - int weapDx = 0, spellDx = 0; - if (!mHealth->getVisible()) - spellDx = weapDx = mWeapBoxBaseLeft - mHealthManaStaminaBaseLeft; - - if (!mWeapBox->getVisible()) - spellDx += mSpellBoxBaseLeft - mWeapBoxBaseLeft; - - mWeaponVisible = mWeapBox->getVisible(); - mSpellVisible = mSpellBox->getVisible(); - if (!mWeaponVisible && !mSpellVisible) - mWeaponSpellBox->setVisible(false); - - mWeapBox->setPosition(mWeapBoxBaseLeft - weapDx, mWeapBox->getTop()); - mSpellBox->setPosition(mSpellBoxBaseLeft - spellDx, mSpellBox->getTop()); - - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - - // effect box can have variable width -> variable left coordinate - int effectsDx = 0; - if (!mMinimapBox->getVisible ()) - effectsDx = (viewSize.width - mMinimapBoxBaseRight) - (viewSize.width - mEffectBoxBaseRight); - - mMapVisible = mMinimapBox->getVisible (); - mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); -} - -void HUD::update() -{ - mSpellIcons->updateWidgets(mEffectBox, true); } diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index c7b7207305..8dda041ca6 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -5,159 +5,165 @@ #include #include -using namespace MWGui; -using namespace MWGui::Widgets; - -MWList::MWList() : - mClient(0) - , mScrollView(0) - , mItemHeight(0) +namespace MWGui { -} -void MWList::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mClient, "Client"); - if (mClient == 0) - mClient = this; - - mScrollView = mClient->createWidgetReal( - "MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), - MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); -} - -void MWList::addItem(const std::string& name) -{ - mItems.push_back(name); -} - -void MWList::addSeparator() -{ - mItems.push_back(""); -} - -void MWList::adjustSize() -{ - redraw(); -} - -void MWList::redraw(bool scrollbarShown) -{ - const int _scrollBarWidth = 24; // fetch this from skin? - const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; - const int spacing = 3; - size_t scrollbarPosition = mScrollView->getScrollPosition(); - - while (mScrollView->getChildCount()) + namespace Widgets { - MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); - } - mItemHeight = 0; - int i=0; - for (std::vector::const_iterator it=mItems.begin(); - it!=mItems.end(); ++it) - { - if (*it != "") + MWList::MWList() : + mClient(0) + , mScrollView(0) + , mItemHeight(0) { - MyGUI::Button* button = mScrollView->createWidget( - "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), - MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); - button->setCaption((*it)); - button->getSubWidgetText()->setWordWrap(true); - button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); - button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); - - int height = button->getTextSize().height; - button->setSize(MyGUI::IntSize(button->getSize().width, height)); - button->setUserData(i); - - mItemHeight += height + spacing; } - else + + void MWList::initialiseOverride() { - MyGUI::ImageBox* separator = mScrollView->createWidget("MW_HLine", - MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth()-4, 18), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - separator->setNeedMouseFocus(false); + Base::initialiseOverride(); - mItemHeight += 18 + spacing; + assignWidget(mClient, "Client"); + if (mClient == 0) + mClient = this; + + mScrollView = mClient->createWidgetReal( + "MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), + MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); } - ++i; + + void MWList::addItem(const std::string& name) + { + mItems.push_back(name); + } + + void MWList::addSeparator() + { + mItems.push_back(""); + } + + void MWList::adjustSize() + { + redraw(); + } + + void MWList::redraw(bool scrollbarShown) + { + const int _scrollBarWidth = 24; // fetch this from skin? + const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; + const int spacing = 3; + size_t scrollbarPosition = mScrollView->getScrollPosition(); + + while (mScrollView->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); + } + + mItemHeight = 0; + int i=0; + for (std::vector::const_iterator it=mItems.begin(); + it!=mItems.end(); ++it) + { + if (*it != "") + { + MyGUI::Button* button = mScrollView->createWidget( + "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), + MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); + button->setCaption((*it)); + button->getSubWidgetText()->setWordWrap(true); + button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); + button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); + + int height = button->getTextSize().height; + button->setSize(MyGUI::IntSize(button->getSize().width, height)); + button->setUserData(i); + + mItemHeight += height + spacing; + } + else + { + MyGUI::ImageBox* separator = mScrollView->createWidget("MW_HLine", + MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth()-4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->setNeedMouseFocus(false); + + mItemHeight += 18 + spacing; + } + ++i; + } + mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); + + if (!scrollbarShown && mItemHeight > mClient->getSize().height) + redraw(true); + + size_t scrollbarRange = mScrollView->getScrollRange(); + if(scrollbarPosition > scrollbarRange) + scrollbarPosition = scrollbarRange; + mScrollView->setScrollPosition(scrollbarPosition); + } + + bool MWList::hasItem(const std::string& name) + { + return (std::find(mItems.begin(), mItems.end(), name) != mItems.end()); + } + + unsigned int MWList::getItemCount() + { + return mItems.size(); + } + + std::string MWList::getItemNameAt(unsigned int at) + { + assert(at < mItems.size() && "List item out of bounds"); + return mItems[at]; + } + + void MWList::removeItem(const std::string& name) + { + assert( std::find(mItems.begin(), mItems.end(), name) != mItems.end() ); + mItems.erase( std::find(mItems.begin(), mItems.end(), name) ); + } + + void MWList::clear() + { + mItems.clear(); + } + + void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + //NB view offset is negative + if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); + } + + void MWList::onItemSelected(MyGUI::Widget* _sender) + { + std::string name = static_cast(_sender)->getCaption(); + int id = *_sender->getUserData(); + eventItemSelected(name, id); + eventWidgetSelected(_sender); + } + + MyGUI::Widget* MWList::getItemWidget(const std::string& name) + { + return mScrollView->findWidget (getName() + "_item_" + name); + } + + size_t MWScrollView::getScrollPosition() + { + return getVScroll()->getScrollPosition(); + } + + void MWScrollView::setScrollPosition(size_t position) + { + getVScroll()->setScrollPosition(position); + } + size_t MWScrollView::getScrollRange() + { + return getVScroll()->getScrollRange(); + } + } - mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); - - if (!scrollbarShown && mItemHeight > mClient->getSize().height) - redraw(true); - - size_t scrollbarRange = mScrollView->getScrollRange(); - if(scrollbarPosition > scrollbarRange) - scrollbarPosition = scrollbarRange; - mScrollView->setScrollPosition(scrollbarPosition); -} - -bool MWList::hasItem(const std::string& name) -{ - return (std::find(mItems.begin(), mItems.end(), name) != mItems.end()); -} - -unsigned int MWList::getItemCount() -{ - return mItems.size(); -} - -std::string MWList::getItemNameAt(unsigned int at) -{ - assert(at < mItems.size() && "List item out of bounds"); - return mItems[at]; -} - -void MWList::removeItem(const std::string& name) -{ - assert( std::find(mItems.begin(), mItems.end(), name) != mItems.end() ); - mItems.erase( std::find(mItems.begin(), mItems.end(), name) ); -} - -void MWList::clear() -{ - mItems.clear(); -} - -void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - //NB view offset is negative - if (mScrollView->getViewOffset().top + _rel*0.3 > 0) - mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); -} - -void MWList::onItemSelected(MyGUI::Widget* _sender) -{ - std::string name = static_cast(_sender)->getCaption(); - int id = *_sender->getUserData(); - eventItemSelected(name, id); - eventWidgetSelected(_sender); -} - -MyGUI::Widget* MWList::getItemWidget(const std::string& name) -{ - return mScrollView->findWidget (getName() + "_item_" + name); -} - -size_t MWScrollView::getScrollPosition() -{ - return getVScroll()->getScrollPosition(); -} - -void MWScrollView::setScrollPosition(size_t position) -{ - getVScroll()->setScrollPosition(position); -} -size_t MWScrollView::getScrollRange() -{ - return getVScroll()->getScrollRange(); } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 1ac1c24480..4a78238ce0 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -13,430 +13,433 @@ #include "widgets.hpp" -using namespace MWGui; - -LocalMapBase::LocalMapBase() - : mCurX(0) - , mCurY(0) - , mInterior(false) - , mFogOfWar(true) - , mLocalMap(NULL) - , mMapDragAndDrop(false) - , mPrefix() - , mChanged(true) - , mLayout(NULL) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) - , mLastDirectionX(0.0f) - , mLastDirectionY(0.0f) - , mCompass(NULL) +namespace MWGui { -} -void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) -{ - mLocalMap = widget; - mLayout = layout; - mMapDragAndDrop = mapDragAndDrop; - mCompass = compass; - - // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each - const int widgetSize = 512; - for (int mx=0; mx<3; ++mx) + LocalMapBase::LocalMapBase() + : mCurX(0) + , mCurY(0) + , mInterior(false) + , mFogOfWar(true) + , mLocalMap(NULL) + , mMapDragAndDrop(false) + , mPrefix() + , mChanged(true) + , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) + , mCompass(NULL) { - for (int my=0; my<3; ++my) + } + + void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) + { + mLocalMap = widget; + mLayout = layout; + mMapDragAndDrop = mapDragAndDrop; + mCompass = compass; + + // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each + const int widgetSize = 512; + for (int mx=0; mx<3; ++mx) { - MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", - MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); - - MyGUI::ImageBox* fog = map->createWidget("ImageBox", - MyGUI::IntCoord(0, 0, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); - - if (!mMapDragAndDrop) + for (int my=0; my<3; ++my) { - map->setNeedMouseFocus(false); - fog->setNeedMouseFocus(false); - } + MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", + MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); - mMapWidgets.push_back(map); - mFogWidgets.push_back(fog); - } - } -} + MyGUI::ImageBox* fog = map->createWidget("ImageBox", + MyGUI::IntCoord(0, 0, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); -void LocalMapBase::setCellPrefix(const std::string& prefix) -{ - mPrefix = prefix; - mChanged = true; -} - -void LocalMapBase::toggleFogOfWar() -{ - mFogOfWar = !mFogOfWar; - applyFogOfWar(); -} - -void LocalMapBase::applyFogOfWar() -{ - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (-1*(my-1))); - MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) - : ""); - } - } - notifyMapChanged (); -} - -void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::setActiveCell(const int x, const int y, bool interior) -{ - if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell - - // clear all previous markers - for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) - { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") - { - MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); - } - } - - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - // map - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (-1*(my-1))); - - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); - else - box->setImageTexture("black.png"); - - - // door markers - - // interior map only consists of one cell, so handle the markers only once - if (interior && (mx != 2 || my != 2)) - continue; - - MWWorld::CellStore* cell; - if (interior) - cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); - else - cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); - - std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); - - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) - { - MWBase::World::DoorMarker marker = *it; - - // convert world coordinates to normalized cell coordinates - MyGUI::IntCoord widgetCoord; - float nX,nY; - int cellDx, cellDy; - if (!interior) + if (!mMapDragAndDrop) { - const int cellSize = 8192; - - nX = (marker.x - cellSize * (x+mx-1)) / cellSize; - nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + map->setNeedMouseFocus(false); + fog->setNeedMouseFocus(false); } + + mMapWidgets.push_back(map); + mFogWidgets.push_back(fog); + } + } + } + + void LocalMapBase::setCellPrefix(const std::string& prefix) + { + mPrefix = prefix; + mChanged = true; + } + + void LocalMapBase::toggleFogOfWar() + { + mFogOfWar = !mFogOfWar; + applyFogOfWar(); + } + + void LocalMapBase::applyFogOfWar() + { + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" + + boost::lexical_cast(mCurY + (-1*(my-1))); + MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; + fog->setImageTexture(mFogOfWar ? + ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" + : "black.png" ) + : ""); + } + } + notifyMapChanged (); + } + + void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) + { + applyFogOfWar (); + } + + void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) + { + applyFogOfWar (); + } + + void LocalMapBase::setActiveCell(const int x, const int y, bool interior) + { + if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell + + // clear all previous markers + for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) + { + if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + { + MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); + } + } + + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + // map + std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + + boost::lexical_cast(y + (-1*(my-1))); + + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; + + if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) + box->setImageTexture(image); else - { - Ogre::Vector2 position (marker.x, marker.y); - MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + box->setImageTexture("black.png"); - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + + // door markers + + // interior map only consists of one cell, so handle the markers only once + if (interior && (mx != 2 || my != 2)) + continue; + + MWWorld::CellStore* cell; + if (interior) + cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); + else + cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); + + std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); + + for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + { + MWBase::World::DoorMarker marker = *it; + + // convert world coordinates to normalized cell coordinates + MyGUI::IntCoord widgetCoord; + float nX,nY; + int cellDx, cellDy; + if (!interior) + { + const int cellSize = 8192; + + nX = (marker.x - cellSize * (x+mx-1)) / cellSize; + nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + } + else + { + Ogre::Vector2 position (marker.x, marker.y); + MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + } + + static int counter = 0; + ++counter; + MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); + markerWidget->setUserString("IsMarker", "true"); + markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); + markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); + + MarkerPosition markerPos; + markerPos.interior = interior; + markerPos.cellX = interior ? cellDx : x + mx - 1; + markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); + markerPos.nX = nX; + markerPos.nY = nY; + + markerWidget->setUserData(markerPos); } - static int counter = 0; - ++counter; - MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", marker.name); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); - markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); - MarkerPosition markerPos; - markerPos.interior = interior; - markerPos.cellX = interior ? cellDx : x + mx - 1; - markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); - markerPos.nX = nX; - markerPos.nY = nY; - - markerWidget->setUserData(markerPos); } - - } - } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; + mInterior = interior; + mCurX = x; + mCurY = y; + mChanged = false; - // fog of war - applyFogOfWar(); + // fog of war + applyFogOfWar(); - // set the compass texture again, because MyGUI determines sorting of ImageBox widgets - // based on the last setImageTexture call - std::string tex = "textures\\compass.dds"; - mCompass->setImageTexture(""); - mCompass->setImageTexture(tex); -} - - -void LocalMapBase::setPlayerPos(const float x, const float y) -{ - if (x == mLastPositionX && y == mLastPositionY) - return; - - notifyPlayerUpdate (); - - MyGUI::IntSize size = mLocalMap->getCanvasSize(); - MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); - MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); - mLocalMap->setViewOffset(pos); - - mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); - mLastPositionX = x; - mLastPositionY = y; -} - -void LocalMapBase::setPlayerDir(const float x, const float y) -{ - if (x == mLastDirectionX && y == mLastDirectionY) - return; - - notifyPlayerUpdate (); - - MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(x,y); - rotatingSubskin->setAngle(angle); - - mLastDirectionX = x; - mLastDirectionY = y; -} - -// ------------------------------------------------------------------------------------------ - -MapWindow::MapWindow(const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout") - , mGlobal(false) -{ - setCoord(500,0,320,300); - - mGlobalMapRender = new MWRender::GlobalMap(cacheDir); - mGlobalMapRender->render(); - - getWidget(mLocalMap, "LocalMap"); - getWidget(mGlobalMap, "GlobalMap"); - getWidget(mGlobalMapImage, "GlobalMapImage"); - getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); - getWidget(mPlayerArrowLocal, "CompassLocal"); - getWidget(mPlayerArrowGlobal, "CompassGlobal"); - - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); - - mGlobalMap->setVisible (false); - - getWidget(mButton, "WorldButton"); - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing("#{sWorld}"); - - getWidget(mEventBoxGlobal, "EventBoxGlobal"); - mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - getWidget(mEventBoxLocal, "EventBoxLocal"); - mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - - LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); -} - -MapWindow::~MapWindow() -{ - delete mGlobalMapRender; -} - -void MapWindow::setCellName(const std::string& cellName) -{ - setTitle("#{sCell=" + cellName + "}"); -} - -void MapWindow::addVisitedLocation(const std::string& name, int x, int y) -{ - float worldX, worldY; - mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); - - MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+6, - worldY * mGlobalMapRender->getHeight()+6, - 12, 12); - - - static int _counter=0; - MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); - ++_counter; - - markerWidget = mEventBoxGlobal->createWidget("", - widgetCoord, MyGUI::Align::Default); - markerWidget->setNeedMouseFocus (true); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); -} - -void MapWindow::cellExplored(int x, int y) -{ - mGlobalMapRender->exploreCell(x,y); -} - -void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - - MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - - if (!mGlobal) - mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); - else - mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); - - - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) -{ - mGlobal = !mGlobal; - mGlobalMap->setVisible(mGlobal); - mLocalMap->setVisible(!mGlobal); - - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); - - if (mGlobal) - globalMapUpdatePlayer (); -} - -void MapWindow::onPinToggled() -{ - MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); -} - -void MapWindow::open() -{ - mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - - for (unsigned int i=0; igetChildCount (); ++i) - { - if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") - mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + // set the compass texture again, because MyGUI determines sorting of ImageBox widgets + // based on the last setImageTexture call + std::string tex = "textures\\compass.dds"; + mCompass->setImageTexture(""); + mCompass->setImageTexture(tex); } - globalMapUpdatePlayer(); - mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); -} - -void MapWindow::globalMapUpdatePlayer () -{ - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); - Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - - // for interiors, we have no choice other than using the last position & direction. - /// \todo save this last position in the savegame? - if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + void LocalMapBase::setPlayerPos(const float x, const float y) { - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + if (x == mLastPositionX && y == mLastPositionY) + return; - MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + notifyPlayerUpdate (); + + MyGUI::IntSize size = mLocalMap->getCanvasSize(); + MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); + MyGUI::IntCoord viewsize = mLocalMap->getCoord(); + MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + mLocalMap->setViewOffset(pos); + + mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); + mLastPositionX = x; + mLastPositionY = y; + } + + void LocalMapBase::setPlayerDir(const float x, const float y) + { + if (x == mLastDirectionX && y == mLastDirectionY) + return; + + notifyPlayerUpdate (); + + MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(dir.x, dir.y); + float angle = std::atan2(x,y); rotatingSubskin->setAngle(angle); - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); - mGlobalMap->setViewOffset(viewoffs); + mLastDirectionX = x; + mLastDirectionY = y; } -} -void MapWindow::notifyPlayerUpdate () -{ - globalMapUpdatePlayer (); -} + // ------------------------------------------------------------------------------------------ -void MapWindow::notifyMapChanged () -{ - // workaround to prevent the map from drawing on top of the button - MyGUI::IntCoord oldCoord = mButton->getCoord (); - MyGUI::Gui::getInstance().destroyWidget (mButton); - mButton = mMainWidget->createWidget("MW_Button", - oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); - mButton->setProperty ("ExpandDirection", "Left"); + MapWindow::MapWindow(const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout") + , mGlobal(false) + { + setCoord(500,0,320,300); + + mGlobalMapRender = new MWRender::GlobalMap(cacheDir); + mGlobalMapRender->render(); + + getWidget(mLocalMap, "LocalMap"); + getWidget(mGlobalMap, "GlobalMap"); + getWidget(mGlobalMapImage, "GlobalMapImage"); + getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); + getWidget(mPlayerArrowLocal, "CompassLocal"); + getWidget(mPlayerArrowGlobal, "CompassGlobal"); + + mGlobalMapImage->setImageTexture("GlobalMap.png"); + mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + + mGlobalMap->setVisible (false); + + getWidget(mButton, "WorldButton"); + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing("#{sWorld}"); + + getWidget(mEventBoxGlobal, "EventBoxGlobal"); + mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + getWidget(mEventBoxLocal, "EventBoxLocal"); + mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); + } + + MapWindow::~MapWindow() + { + delete mGlobalMapRender; + } + + void MapWindow::setCellName(const std::string& cellName) + { + setTitle("#{sCell=" + cellName + "}"); + } + + void MapWindow::addVisitedLocation(const std::string& name, int x, int y) + { + float worldX, worldY; + mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); + + MyGUI::IntCoord widgetCoord( + worldX * mGlobalMapRender->getWidth()+6, + worldY * mGlobalMapRender->getHeight()+6, + 12, 12); + + + static int _counter=0; + MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + ++_counter; + + markerWidget = mEventBoxGlobal->createWidget("", + widgetCoord, MyGUI::Align::Default); + markerWidget->setNeedMouseFocus (true); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + } + + void MapWindow::cellExplored(int x, int y) + { + mGlobalMapRender->exploreCell(x,y); + } + + void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + if (_id!=MyGUI::MouseButton::Left) return; + mLastDragPos = MyGUI::IntPoint(_left, _top); + } + + void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + if (_id!=MyGUI::MouseButton::Left) return; + + MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; + + if (!mGlobal) + mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + else + mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); + + + mLastDragPos = MyGUI::IntPoint(_left, _top); + } + + void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) + { + mGlobal = !mGlobal; + mGlobalMap->setVisible(mGlobal); + mLocalMap->setVisible(!mGlobal); + + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + + if (mGlobal) + globalMapUpdatePlayer (); + } + + void MapWindow::onPinToggled() + { + MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); + } + + void MapWindow::open() + { + mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + + for (unsigned int i=0; igetChildCount (); ++i) + { + if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") + mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + } + + globalMapUpdatePlayer(); + + mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); + } + + void MapWindow::globalMapUpdatePlayer () + { + Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); + Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); + + float worldX, worldY; + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); + worldX *= mGlobalMapRender->getWidth(); + worldY *= mGlobalMapRender->getHeight(); + + + // for interiors, we have no choice other than using the last position & direction. + /// \todo save this last position in the savegame? + if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + { + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + + MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(dir.x, dir.y); + rotatingSubskin->setAngle(angle); + + // set the view offset so that player is in the center + MyGUI::IntSize viewsize = mGlobalMap->getSize(); + MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); + mGlobalMap->setViewOffset(viewoffs); + } + } + + void MapWindow::notifyPlayerUpdate () + { + globalMapUpdatePlayer (); + } + + void MapWindow::notifyMapChanged () + { + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + } - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 8e53380bde..876fb35220 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -5,411 +5,414 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" -using namespace MWGui; - -MessageBoxManager::MessageBoxManager () +namespace MWGui { - // defines - mMessageBoxSpeed = 0.1; - mInterMessageBoxe = NULL; -} -void MessageBoxManager::onFrame (float frameDuration) -{ - std::vector::iterator it; - for(it = mTimers.begin(); it != mTimers.end();) + MessageBoxManager::MessageBoxManager () { - // if this messagebox is already deleted, remove the timer and move on - if (std::find(mMessageBoxes.begin(), mMessageBoxes.end(), it->messageBox) == mMessageBoxes.end()) - { - it = mTimers.erase(it); - continue; - } + // defines + mMessageBoxSpeed = 0.1; + mInterMessageBoxe = NULL; + } - it->current += frameDuration; - if(it->current >= it->max) + void MessageBoxManager::onFrame (float frameDuration) + { + std::vector::iterator it; + for(it = mTimers.begin(); it != mTimers.end();) { - it->messageBox->mMarkedToDelete = true; - - if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one + // if this messagebox is already deleted, remove the timer and move on + if (std::find(mMessageBoxes.begin(), mMessageBoxes.end(), it->messageBox) == mMessageBoxes.end()) { - // collect all with mMarkedToDelete and delete them. - // and place the other messageboxes on the right position - int height = 0; - std::vector::iterator it2 = mMessageBoxes.begin(); - while(it2 != mMessageBoxes.end()) + it = mTimers.erase(it); + continue; + } + + it->current += frameDuration; + if(it->current >= it->max) + { + it->messageBox->mMarkedToDelete = true; + + if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one { - if((*it2)->mMarkedToDelete) + // collect all with mMarkedToDelete and delete them. + // and place the other messageboxes on the right position + int height = 0; + std::vector::iterator it2 = mMessageBoxes.begin(); + while(it2 != mMessageBoxes.end()) { - delete (*it2); - it2 = mMessageBoxes.erase(it2); - } - else { - (*it2)->update(height); - height += (*it2)->getHeight(); - it2++; + if((*it2)->mMarkedToDelete) + { + delete (*it2); + it2 = mMessageBoxes.erase(it2); + } + else { + (*it2)->update(height); + height += (*it2)->getHeight(); + it2++; + } } } + it = mTimers.erase(it); + } + else + { + it++; + } + } + + if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; + MWBase::Environment::get().getInputManager()->changeInputMode( + MWBase::Environment::get().getWindowManager()->isGuiMode()); + } + } + + void MessageBoxManager::createMessageBox (const std::string& message) + { + MessageBox *box = new MessageBox(*this, message); + + removeMessageBox(message.length()*mMessageBoxSpeed, box); + + mMessageBoxes.push_back(box); + std::vector::iterator it; + + if(mMessageBoxes.size() > 3) { + delete *mMessageBoxes.begin(); + mMessageBoxes.erase(mMessageBoxes.begin()); + } + + int height = 0; + for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + { + (*it)->update(height); + height += (*it)->getHeight(); + } + } + + bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) + { + if(mInterMessageBoxe != NULL) { + throw std::runtime_error("There is a message box already"); + } + + mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); + + return true; + } + + bool MessageBoxManager::isInteractiveMessageBox () + { + return mInterMessageBoxe != NULL; + } + + void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox) + { + MessageBoxManagerTimer timer; + timer.current = 0; + timer.max = time; + timer.messageBox = msgbox; + + mTimers.insert(mTimers.end(), timer); + } + + bool MessageBoxManager::removeMessageBox (MessageBox *msgbox) + { + std::vector::iterator it; + for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + { + if((*it) == msgbox) + { + delete (*it); + mMessageBoxes.erase(it); + return true; + } + } + return false; + } + + void MessageBoxManager::setMessageBoxSpeed (int speed) + { + mMessageBoxSpeed = speed; + } + + void MessageBoxManager::enterPressed () + { + if(mInterMessageBoxe != NULL) + mInterMessageBoxe->enterPressed(); + } + + int MessageBoxManager::readPressedButton () + { + if(mInterMessageBoxe != NULL) + { + return mInterMessageBoxe->readPressedButton(); + } + return -1; + } + + + + + MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) + : Layout("openmw_messagebox.layout") + , mMessageBoxManager(parMessageBoxManager) + , mMessage(message) + { + // defines + mFixedWidth = 300; + mBottomPadding = 20; + mNextBoxPadding = 20; + mMarkedToDelete = false; + + getWidget(mMessageWidget, "message"); + + mMessageWidget->setOverflowToTheLeft(true); + mMessageWidget->setCaptionWithReplacing(mMessage); + + MyGUI::IntSize size; + size.width = mFixedWidth; + size.height = 100; // dummy + + MyGUI::IntCoord coord; + coord.left = 10; // dummy + coord.top = 10; // dummy + + mMessageWidget->setSize(size); + + MyGUI::IntSize textSize = mMessageWidget->getTextSize(); + + size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box + + mMainWidget->setSize(size); + size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0") + mMessageWidget->setSize(size); + } + + void MessageBox::update (int height) + { + MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntCoord coord; + coord.left = (gameWindowSize.width - mFixedWidth)/2; + coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); + + MyGUI::IntSize size; + size.width = mFixedWidth; + size.height = mHeight; + + mMainWidget->setCoord(coord); + mMainWidget->setSize(size); + mMainWidget->setVisible(true); + } + + int MessageBox::getHeight () + { + return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox + } + + + + InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) + : WindowModal("openmw_interactive_messagebox.layout") + , mMessageBoxManager(parMessageBoxManager) + , mButtonPressed(-1) + { + WindowModal::open(); + + int fixedWidth = 500; + int textPadding = 10; // padding between text-widget and main-widget + int textButtonPadding = 20; // padding between the text-widget und the button-widget + int buttonLeftPadding = 10; // padding between the buttons if horizontal + int buttonTopPadding = 5; // ^-- if vertical + int buttonPadding = 5; // padding between button label and button itself + int buttonMainPadding = 10; // padding between buttons and bottom of the main widget + + mMarkedToDelete = false; + + + getWidget(mMessageWidget, "message"); + getWidget(mButtonsWidget, "buttons"); + + mMessageWidget->setOverflowToTheLeft(true); + mMessageWidget->setCaptionWithReplacing(message); + + MyGUI::IntSize textSize = mMessageWidget->getTextSize(); + + MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + + int biggestButtonWidth = 0; + int buttonWidth = 0; + int buttonsWidth = 0; + int buttonHeight = 0; + MyGUI::IntCoord dummyCoord(0, 0, 0, 0); + + std::vector::const_iterator it; + for(it = buttons.begin(); it != buttons.end(); ++it) + { + MyGUI::Button* button = mButtonsWidget->createWidget( + MyGUI::WidgetStyle::Child, + std::string("MW_Button"), + dummyCoord, + MyGUI::Align::Default); + button->setCaptionWithReplacing(*it); + + button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); + + mButtons.push_back(button); + + buttonWidth = button->getTextSize().width + 2*buttonPadding + buttonLeftPadding; + buttonsWidth += buttonWidth; + buttonHeight = button->getTextSize().height + 2*buttonPadding + buttonTopPadding; + + if(buttonWidth > biggestButtonWidth) + { + biggestButtonWidth = buttonWidth; + } + } + buttonsWidth += buttonLeftPadding; + + MyGUI::IntSize mainWidgetSize; + if(buttonsWidth < fixedWidth) + { + // on one line + if(textSize.width + 2*textPadding < buttonsWidth) + { + mainWidgetSize.width = buttonsWidth; + } + else + { + mainWidgetSize.width = textSize.width + 3*textPadding; + } + mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; + + MyGUI::IntCoord absCoord; + absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + mMainWidget->setCoord(absCoord); + mMainWidget->setSize(mainWidgetSize); + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + mMessageWidget->setCoord(messageWidgetCoord); + + mMessageWidget->setSize(textSize); + + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonCord.left = left; + buttonCord.top = textSize.height + textButtonPadding; + + buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; + buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + left += buttonSize.width + buttonLeftPadding; } - it = mTimers.erase(it); } else { - it++; + // among each other + if(biggestButtonWidth > textSize.width) { + mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; + } + else { + mainWidgetSize.width = textSize.width + 3*textPadding; + } + mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; + + mMainWidget->setSize(mainWidgetSize); + + MyGUI::IntCoord absCoord; + absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + mMainWidget->setCoord(absCoord); + mMainWidget->setSize(mainWidgetSize); + + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + mMessageWidget->setCoord(messageWidgetCoord); + + mMessageWidget->setSize(textSize); + + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + + int top = textButtonPadding + buttonTopPadding + textSize.height; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; + buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; + + buttonCord.top = top; + buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + top += buttonSize.height + 2*buttonTopPadding; + } + } } - if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { - delete mInterMessageBoxe; - mInterMessageBoxe = NULL; - MWBase::Environment::get().getInputManager()->changeInputMode( - MWBase::Environment::get().getWindowManager()->isGuiMode()); - } -} - -void MessageBoxManager::createMessageBox (const std::string& message) -{ - MessageBox *box = new MessageBox(*this, message); - - removeMessageBox(message.length()*mMessageBoxSpeed, box); - - mMessageBoxes.push_back(box); - std::vector::iterator it; - - if(mMessageBoxes.size() > 3) { - delete *mMessageBoxes.begin(); - mMessageBoxes.erase(mMessageBoxes.begin()); - } - - int height = 0; - for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + void InteractiveMessageBox::enterPressed() { - (*it)->update(height); - height += (*it)->getHeight(); - } -} - -bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) -{ - if(mInterMessageBoxe != NULL) { - throw std::runtime_error("There is a message box already"); - } - - mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); - - return true; -} - -bool MessageBoxManager::isInteractiveMessageBox () -{ - return mInterMessageBoxe != NULL; -} - -void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox) -{ - MessageBoxManagerTimer timer; - timer.current = 0; - timer.max = time; - timer.messageBox = msgbox; - - mTimers.insert(mTimers.end(), timer); -} - -bool MessageBoxManager::removeMessageBox (MessageBox *msgbox) -{ - std::vector::iterator it; - for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) - { - if((*it) == msgbox) - { - delete (*it); - mMessageBoxes.erase(it); - return true; - } - } - return false; -} - -void MessageBoxManager::setMessageBoxSpeed (int speed) -{ - mMessageBoxSpeed = speed; -} - -void MessageBoxManager::enterPressed () -{ - if(mInterMessageBoxe != NULL) - mInterMessageBoxe->enterPressed(); -} - -int MessageBoxManager::readPressedButton () -{ - if(mInterMessageBoxe != NULL) - { - return mInterMessageBoxe->readPressedButton(); - } - return -1; -} - - - - -MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) - : Layout("openmw_messagebox.layout") - , mMessageBoxManager(parMessageBoxManager) - , mMessage(message) -{ - // defines - mFixedWidth = 300; - mBottomPadding = 20; - mNextBoxPadding = 20; - mMarkedToDelete = false; - - getWidget(mMessageWidget, "message"); - - mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->setCaptionWithReplacing(mMessage); - - MyGUI::IntSize size; - size.width = mFixedWidth; - size.height = 100; // dummy - - MyGUI::IntCoord coord; - coord.left = 10; // dummy - coord.top = 10; // dummy - - mMessageWidget->setSize(size); - - MyGUI::IntSize textSize = mMessageWidget->getTextSize(); - - size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box - - mMainWidget->setSize(size); - size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0") - mMessageWidget->setSize(size); -} - -void MessageBox::update (int height) -{ - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntCoord coord; - coord.left = (gameWindowSize.width - mFixedWidth)/2; - coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); - - MyGUI::IntSize size; - size.width = mFixedWidth; - size.height = mHeight; - - mMainWidget->setCoord(coord); - mMainWidget->setSize(size); - mMainWidget->setVisible(true); -} - -int MessageBox::getHeight () -{ - return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox -} - - - -InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : WindowModal("openmw_interactive_messagebox.layout") - , mMessageBoxManager(parMessageBoxManager) - , mButtonPressed(-1) -{ - WindowModal::open(); - - int fixedWidth = 500; - int textPadding = 10; // padding between text-widget and main-widget - int textButtonPadding = 20; // padding between the text-widget und the button-widget - int buttonLeftPadding = 10; // padding between the buttons if horizontal - int buttonTopPadding = 5; // ^-- if vertical - int buttonPadding = 5; // padding between button label and button itself - int buttonMainPadding = 10; // padding between buttons and bottom of the main widget - - mMarkedToDelete = false; - - - getWidget(mMessageWidget, "message"); - getWidget(mButtonsWidget, "buttons"); - - mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->setCaptionWithReplacing(message); - - MyGUI::IntSize textSize = mMessageWidget->getTextSize(); - - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - - int biggestButtonWidth = 0; - int buttonWidth = 0; - int buttonsWidth = 0; - int buttonHeight = 0; - MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - - std::vector::const_iterator it; - for(it = buttons.begin(); it != buttons.end(); ++it) - { - MyGUI::Button* button = mButtonsWidget->createWidget( - MyGUI::WidgetStyle::Child, - std::string("MW_Button"), - dummyCoord, - MyGUI::Align::Default); - button->setCaptionWithReplacing(*it); - - button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); - - mButtons.push_back(button); - - buttonWidth = button->getTextSize().width + 2*buttonPadding + buttonLeftPadding; - buttonsWidth += buttonWidth; - buttonHeight = button->getTextSize().height + 2*buttonPadding + buttonTopPadding; - - if(buttonWidth > biggestButtonWidth) - { - biggestButtonWidth = buttonWidth; - } - } - buttonsWidth += buttonLeftPadding; - - MyGUI::IntSize mainWidgetSize; - if(buttonsWidth < fixedWidth) - { - // on one line - if(textSize.width + 2*textPadding < buttonsWidth) - { - mainWidgetSize.width = buttonsWidth; - } - else - { - mainWidgetSize.width = textSize.width + 3*textPadding; - } - mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; - - MyGUI::IntCoord absCoord; - absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; - absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - - mMainWidget->setCoord(absCoord); - mMainWidget->setSize(mainWidgetSize); - - MyGUI::IntCoord messageWidgetCoord; - messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; - messageWidgetCoord.top = textPadding; - mMessageWidget->setCoord(messageWidgetCoord); - - mMessageWidget->setSize(textSize); - - MyGUI::IntCoord buttonCord; - MyGUI::IntSize buttonSize(0, buttonHeight); - int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonCord.left = left; - buttonCord.top = textSize.height + textButtonPadding; - - buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; - - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); - - left += buttonSize.width + buttonLeftPadding; + if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) + { + buttonActivated(*button); + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); + break; + } } + } - else + + void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) { - // among each other - if(biggestButtonWidth > textSize.width) { - mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; - } - else { - mainWidgetSize.width = textSize.width + 3*textPadding; - } - mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; - - mMainWidget->setSize(mainWidgetSize); - - MyGUI::IntCoord absCoord; - absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; - absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - - mMainWidget->setCoord(absCoord); - mMainWidget->setSize(mainWidgetSize); - - - MyGUI::IntCoord messageWidgetCoord; - messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; - messageWidgetCoord.top = textPadding; - mMessageWidget->setCoord(messageWidgetCoord); - - mMessageWidget->setSize(textSize); - - MyGUI::IntCoord buttonCord; - MyGUI::IntSize buttonSize(0, buttonHeight); - - int top = textButtonPadding + buttonTopPadding + textSize.height; + buttonActivated (pressed); + } + void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) + { + mMarkedToDelete = true; + int index = 0; std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; - - buttonCord.top = top; - buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ - - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); - - top += buttonSize.height + 2*buttonTopPadding; + if(*button == pressed) + { + mButtonPressed = index; + mMessageBoxManager.onButtonPressed(mButtonPressed); + return; + } + index++; } - } -} -void InteractiveMessageBox::enterPressed() -{ - - std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + int InteractiveMessageBox::readPressedButton () { - if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) - { - buttonActivated(*button); - MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); - break; - } + int pressed = mButtonPressed; + mButtonPressed = -1; + return pressed; } } - -void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) -{ - buttonActivated (pressed); -} - -void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) -{ - mMarkedToDelete = true; - int index = 0; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) - { - if(*button == pressed) - { - mButtonPressed = index; - mMessageBoxManager.onButtonPressed(mButtonPressed); - return; - } - index++; - } -} - -int InteractiveMessageBox::readPressedButton () -{ - int pressed = mButtonPressed; - mButtonPressed = -1; - return pressed; -} diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index c031ad6b68..0a7374085f 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -10,435 +10,437 @@ #include "tooltips.hpp" -using namespace MWGui; -using namespace Widgets; - namespace { -int wrap(int index, int max) -{ - if (index < 0) - return max - 1; - else if (index >= max) - return 0; - else - return index; -} - -int countParts(const std::string &part, const std::string &race, bool male) -{ - /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs - const MWWorld::Store &store = - MWBase::Environment::get().getWorld()->getStore().get(); - - std::string prefix = - "b_n_" + race + ((male) ? "_m_" : "_f_") + part; - - std::string suffix; - suffix.reserve(prefix.size() + 3); - - int count = -1; - do { - ++count; - suffix = "_" + (boost::format("%02d") % (count + 1)).str(); + int wrap(int index, int max) + { + if (index < 0) + return max - 1; + else if (index >= max) + return 0; + else + return index; } - while (store.search(prefix + suffix) != 0); - if (count == 0 && part == "hair") { - count = -1; + int countParts(const std::string &part, const std::string &race, bool male) + { + /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string prefix = + "b_n_" + race + ((male) ? "_m_" : "_f_") + part; + + std::string suffix; + suffix.reserve(prefix.size() + 3); + + int count = -1; do { ++count; - suffix = (boost::format("%02d") % (count + 1)).str(); + suffix = "_" + (boost::format("%02d") % (count + 1)).str(); } while (store.search(prefix + suffix) != 0); + + if (count == 0 && part == "hair") { + count = -1; + do { + ++count; + suffix = (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + } + return count; } - return count; -} } -RaceDialog::RaceDialog() - : WindowModal("openmw_chargen_race.layout") - , mGenderIndex(0) - , mFaceIndex(0) - , mHairIndex(0) - , mFaceCount(10) - , mHairCount(14) - , mCurrentAngle(0) +namespace MWGui { - // Centre dialog - center(); - setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); - getWidget(mPreviewImage, "PreviewImage"); - - getWidget(mHeadRotate, "HeadRotate"); - mHeadRotate->setScrollRange(50); - mHeadRotate->setScrollPosition(25); - mHeadRotate->setScrollViewPage(10); - mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); - - // Set up next/previous buttons - MyGUI::Button *prevButton, *nextButton; - - setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); - getWidget(prevButton, "PrevGenderButton"); - getWidget(nextButton, "NextGenderButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); - - setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); - getWidget(prevButton, "PrevFaceButton"); - getWidget(nextButton, "NextFaceButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); - - setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); - getWidget(prevButton, "PrevHairButton"); - getWidget(nextButton, "NextHairButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - - setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); - getWidget(mRaceList, "RaceList"); - mRaceList->setScrollVisible(true); - mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - - setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); - getWidget(mSkillList, "SkillList"); - setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); - getWidget(mSpellPowerList, "SpellPowerList"); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); - - updateRaces(); - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -void RaceDialog::open() -{ - WindowModal::open(); - - updateRaces(); - updateSkills(); - updateSpellPowers(); - - mPreview = new MWRender::RaceSelectionPreview(); - mPreview->setup(); - mPreview->update (0); - - const ESM::NPC proto = mPreview->getPrototype(); - setRaceId(proto.mRace); - recountParts(); - - std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); - mFaceIndex = boost::lexical_cast(index) - 1; - - index = proto.mHair.substr(proto.mHair.size() - 2, 2); - mHairIndex = boost::lexical_cast(index) - 1; - - mPreviewImage->setImageTexture ("CharacterHeadPreview"); -} - - -void RaceDialog::setRaceId(const std::string &raceId) -{ - mCurrentRaceId = raceId; - mRaceList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mRaceList->getItemCount(); - for (size_t i = 0; i < count; ++i) + RaceDialog::RaceDialog() + : WindowModal("openmw_chargen_race.layout") + , mGenderIndex(0) + , mFaceIndex(0) + , mHairIndex(0) + , mFaceCount(10) + , mHairCount(14) + , mCurrentAngle(0) { - if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) + // Centre dialog + center(); + + setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); + getWidget(mPreviewImage, "PreviewImage"); + + getWidget(mHeadRotate, "HeadRotate"); + mHeadRotate->setScrollRange(50); + mHeadRotate->setScrollPosition(25); + mHeadRotate->setScrollViewPage(10); + mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); + + // Set up next/previous buttons + MyGUI::Button *prevButton, *nextButton; + + setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); + getWidget(prevButton, "PrevGenderButton"); + getWidget(nextButton, "NextGenderButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); + + setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); + getWidget(prevButton, "PrevFaceButton"); + getWidget(nextButton, "NextFaceButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); + + setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); + getWidget(prevButton, "PrevHairButton"); + getWidget(nextButton, "NextHairButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); + + setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); + getWidget(mRaceList, "RaceList"); + mRaceList->setScrollVisible(true); + mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + + setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); + getWidget(mSkillList, "SkillList"); + setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); + getWidget(mSpellPowerList, "SpellPowerList"); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); + + updateRaces(); + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void RaceDialog::open() + { + WindowModal::open(); + + updateRaces(); + updateSkills(); + updateSpellPowers(); + + mPreview = new MWRender::RaceSelectionPreview(); + mPreview->setup(); + mPreview->update (0); + + const ESM::NPC proto = mPreview->getPrototype(); + setRaceId(proto.mRace); + recountParts(); + + std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); + mFaceIndex = boost::lexical_cast(index) - 1; + + index = proto.mHair.substr(proto.mHair.size() - 2, 2); + mHairIndex = boost::lexical_cast(index) - 1; + + mPreviewImage->setImageTexture ("CharacterHeadPreview"); + } + + + void RaceDialog::setRaceId(const std::string &raceId) + { + mCurrentRaceId = raceId; + mRaceList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mRaceList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mRaceList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; + if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) + { + mRaceList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } + } + + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::close() + { + delete mPreview; + mPreview = 0; + } + + // widget controls + + void RaceDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE) + return; + eventDone(this); + } + + void RaceDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) + { + float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2; + float diff = angle - mCurrentAngle; + mPreview->update (diff); + mCurrentAngle += diff; + } + + void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) + { + mGenderIndex = wrap(mGenderIndex - 1, 2); + + recountParts(); + updatePreview(); + } + + void RaceDialog::onSelectNextGender(MyGUI::Widget*) + { + mGenderIndex = wrap(mGenderIndex + 1, 2); + + recountParts(); + updatePreview(); + } + + void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) + { + do + mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); + while (!isFacePlayable()); + updatePreview(); + } + + void RaceDialog::onSelectNextFace(MyGUI::Widget*) + { + do + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + while (!isFacePlayable()); + updatePreview(); + } + + void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) + { + do + mHairIndex = wrap(mHairIndex - 1, mHairCount); + while (!isHairPlayable()); + updatePreview(); + } + + void RaceDialog::onSelectNextHair(MyGUI::Widget*) + { + do + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isHairPlayable()); + updatePreview(); + } + + bool RaceDialog::isFacePlayable() + { + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(prefix + "head_" + headIndex) == 0) + return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + } + + bool RaceDialog::isHairPlayable() + { + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + if (parts.search(prefix + "hair_" + hairIndex) == 0) + return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + } + + void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) + { + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + const std::string *raceId = mRaceList->getItemDataAt(_index); + if (boost::iequals(mCurrentRaceId, *raceId)) + return; + + mCurrentRaceId = *raceId; + + recountParts(); + + updatePreview(); + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::recountParts() + { + mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); + mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + + mFaceIndex = 0; + mHairIndex = 0; + + while (!isHairPlayable()) + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isFacePlayable()) + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + } + + // update widget content + + void RaceDialog::updatePreview() + { + ESM::NPC record = mPreview->getPrototype(); + record.mRace = mCurrentRaceId; + record.setIsMale(mGenderIndex == 0); + + std::string prefix = + "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + record.mHead = prefix + "head_" + headIndex; + record.mHair = prefix + "hair_" + hairIndex; + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(record.mHair) == 0) { + record.mHair = prefix + "hair" + hairIndex; + } + mPreview->setPrototype(record); + } + + void RaceDialog::updateRaces() + { + mRaceList->removeAllItems(); + + const MWWorld::Store &races = + MWBase::Environment::get().getWorld()->getStore().get(); + + + int index = 0; + MWWorld::Store::iterator it = races.begin(); + for (; it != races.end(); ++it) + { + bool playable = it->mData.mFlags & ESM::Race::Playable; + if (!playable) // Only display playable races + continue; + + mRaceList->addItem(it->mName, it->mId); + if (boost::iequals(it->mId, mCurrentRaceId)) + mRaceList->setIndexSelected(index); + ++index; } } - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::close() -{ - delete mPreview; - mPreview = 0; -} - -// widget controls - -void RaceDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void RaceDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) -{ - float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2; - float diff = angle - mCurrentAngle; - mPreview->update (diff); - mCurrentAngle += diff; -} - -void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) -{ - mGenderIndex = wrap(mGenderIndex - 1, 2); - - recountParts(); - updatePreview(); -} - -void RaceDialog::onSelectNextGender(MyGUI::Widget*) -{ - mGenderIndex = wrap(mGenderIndex + 1, 2); - - recountParts(); - updatePreview(); -} - -void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) -{ - do - mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); - while (!isFacePlayable()); - updatePreview(); -} - -void RaceDialog::onSelectNextFace(MyGUI::Widget*) -{ - do - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); - while (!isFacePlayable()); - updatePreview(); -} - -void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) -{ - do - mHairIndex = wrap(mHairIndex - 1, mHairCount); - while (!isHairPlayable()); - updatePreview(); -} - -void RaceDialog::onSelectNextHair(MyGUI::Widget*) -{ - do - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isHairPlayable()); - updatePreview(); -} - -bool RaceDialog::isFacePlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(prefix + "head_" + headIndex) == 0) - return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -bool RaceDialog::isHairPlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - if (parts.search(prefix + "hair_" + hairIndex) == 0) - return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - const std::string *raceId = mRaceList->getItemDataAt(_index); - if (boost::iequals(mCurrentRaceId, *raceId)) - return; - - mCurrentRaceId = *raceId; - - recountParts(); - - updatePreview(); - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::recountParts() -{ - mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); - mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); - - mFaceIndex = 0; - mHairIndex = 0; - - while (!isHairPlayable()) - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isFacePlayable()) - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); -} - -// update widget content - -void RaceDialog::updatePreview() -{ - ESM::NPC record = mPreview->getPrototype(); - record.mRace = mCurrentRaceId; - record.setIsMale(mGenderIndex == 0); - - std::string prefix = - "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - record.mHead = prefix + "head_" + headIndex; - record.mHair = prefix + "hair_" + hairIndex; - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(record.mHair) == 0) { - record.mHair = prefix + "hair" + hairIndex; - } - mPreview->setPrototype(record); -} - -void RaceDialog::updateRaces() -{ - mRaceList->removeAllItems(); - - const MWWorld::Store &races = - MWBase::Environment::get().getWorld()->getStore().get(); - - - int index = 0; - MWWorld::Store::iterator it = races.begin(); - for (; it != races.end(); ++it) + void RaceDialog::updateSkills() { - bool playable = it->mData.mFlags & ESM::Race::Playable; - if (!playable) // Only display playable races - continue; + for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillItems.clear(); - mRaceList->addItem(it->mName, it->mId); - if (boost::iequals(it->mId, mCurrentRaceId)) - mRaceList->setIndexSelected(index); - ++index; - } -} - -void RaceDialog::updateSkills() -{ - for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillItems.clear(); - - if (mCurrentRaceId.empty()) - return; - - MWSkillPtr skillWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.get().find(mCurrentRaceId); - int count = sizeof(race->mData.mBonus)/sizeof(race->mData.mBonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? - for (int i = 0; i < count; ++i) - { - int skillId = race->mData.mBonus[i].mSkill; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - - skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, - std::string("Skill") + boost::lexical_cast(i)); - skillWidget->setSkillNumber(skillId); - skillWidget->setSkillValue(MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); - ToolTips::createSkillToolTip(skillWidget, skillId); - - - mSkillItems.push_back(skillWidget); - - coord1.top += lineHeight; - } -} - -void RaceDialog::updateSpellPowers() -{ - for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSpellPowerItems.clear(); - - if (mCurrentRaceId.empty()) - return; - - MWSpellPtr spellPowerWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.get().find(mCurrentRaceId); - - std::vector::const_iterator it = race->mPowers.mList.begin(); - std::vector::const_iterator end = race->mPowers.mList.end(); - for (int i = 0; it != end; ++it) - { - const std::string &spellpower = *it; - spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); - spellPowerWidget->setSpellId(spellpower); - spellPowerWidget->setUserString("ToolTipType", "Spell"); - spellPowerWidget->setUserString("Spell", spellpower); - - mSpellPowerItems.push_back(spellPowerWidget); - - coord.top += lineHeight; - ++i; + if (mCurrentRaceId.empty()) + return; + + Widgets::MWSkillPtr skillWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mCurrentRaceId); + int count = sizeof(race->mData.mBonus)/sizeof(race->mData.mBonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? + for (int i = 0; i < count; ++i) + { + int skillId = race->mData.mBonus[i].mSkill; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + + skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, + std::string("Skill") + boost::lexical_cast(i)); + skillWidget->setSkillNumber(skillId); + skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); + ToolTips::createSkillToolTip(skillWidget, skillId); + + + mSkillItems.push_back(skillWidget); + + coord1.top += lineHeight; + } } + + void RaceDialog::updateSpellPowers() + { + for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSpellPowerItems.clear(); + + if (mCurrentRaceId.empty()) + return; + + Widgets::MWSpellPtr spellPowerWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mCurrentRaceId); + + std::vector::const_iterator it = race->mPowers.mList.begin(); + std::vector::const_iterator end = race->mPowers.mList.end(); + for (int i = 0; it != end; ++it) + { + const std::string &spellpower = *it; + spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); + spellPowerWidget->setSpellId(spellpower); + spellPowerWidget->setUserString("ToolTipType", "Spell"); + spellPowerWidget->setUserString("Spell", spellpower); + + mSpellPowerItems.push_back(spellPowerWidget); + + coord.top += lineHeight; + ++i; + } + } + } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 31f5d737b9..824929b67e 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -11,357 +11,359 @@ #undef min #undef max -using namespace MWGui; -using namespace Widgets; - -const int ReviewDialog::sLineHeight = 18; - -ReviewDialog::ReviewDialog() - : WindowModal("openmw_chargen_review.layout") - , mLastPos(0) +namespace MWGui { - // Centre dialog - center(); - // Setup static stats - MyGUI::Button* button; - getWidget(mNameWidget, "NameText"); - getWidget(button, "NameButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; + const int ReviewDialog::sLineHeight = 18; - getWidget(mRaceWidget, "RaceText"); - getWidget(button, "RaceButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; - - getWidget(mClassWidget, "ClassText"); - getWidget(button, "ClassButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; - - getWidget(mBirthSignWidget, "SignText"); - getWidget(button, "SignButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; - - // Setup dynamic stats - getWidget(mHealth, "Health"); - mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); - mHealth->setValue(45, 45); - - getWidget(mMagicka, "Magicka"); - mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); - mMagicka->setValue(50, 50); - - getWidget(mFatigue, "Fatigue"); - mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); - mFatigue->setValue(160, 160); - - // Setup attributes - - MWAttributePtr attribute; - for (int idx = 0; idx < ESM::Attribute::Length; ++idx) + ReviewDialog::ReviewDialog() + : WindowModal("openmw_chargen_review.layout") + , mLastPos(0) { - getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); - mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); - attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); - attribute->setAttributeValue(MWAttribute::AttributeValue(0, 0)); - } + // Centre dialog + center(); - // Setup skills - getWidget(mSkillView, "SkillView"); - mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + // Setup static stats + MyGUI::Button* button; + getWidget(mNameWidget, "NameText"); + getWidget(button, "NameButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::make_pair(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); - } + getWidget(mRaceWidget, "RaceText"); + getWidget(button, "RaceButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); + getWidget(mClassWidget, "ClassText"); + getWidget(button, "ClassButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); -} + getWidget(mBirthSignWidget, "SignText"); + getWidget(button, "SignButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; -void ReviewDialog::open() -{ - WindowModal::open(); - updateSkillArea(); -} + // Setup dynamic stats + getWidget(mHealth, "Health"); + mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); + mHealth->setValue(45, 45); -void ReviewDialog::setPlayerName(const std::string &name) -{ - mNameWidget->setCaption(name); -} + getWidget(mMagicka, "Magicka"); + mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); + mMagicka->setValue(50, 50); -void ReviewDialog::setRace(const std::string &raceId) -{ - mRaceId = raceId; + getWidget(mFatigue, "Fatigue"); + mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); + mFatigue->setValue(160, 160); - const ESM::Race *race = - MWBase::Environment::get().getWorld()->getStore().get().search(mRaceId); - if (race) - { - ToolTips::createRaceToolTip(mRaceWidget, race); - mRaceWidget->setCaption(race->mName); - } -} + // Setup attributes -void ReviewDialog::setClass(const ESM::Class& class_) -{ - mKlass = class_; - mClassWidget->setCaption(mKlass.mName); - ToolTips::createClassToolTip(mClassWidget, mKlass); -} - -void ReviewDialog::setBirthSign(const std::string& signId) -{ - mBirthSignId = signId; - - const ESM::BirthSign *sign = - MWBase::Environment::get().getWorld()->getStore().get().search(mBirthSignId); - if (sign) - { - mBirthSignWidget->setCaption(sign->mName); - ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); - } -} - -void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) -{ - mHealth->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); -} - -void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) -{ - mMagicka->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); -} - -void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) -{ - mFatigue->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); -} - -void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) -{ - std::map::iterator attr = mAttributeWidgets.find(static_cast(attributeId)); - if (attr == mAttributeWidgets.end()) - return; - - attr->second->setAttributeValue(value); -} - -void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value) -{ - mSkillValues[skillId] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } - -} - -void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); - } - - updateSkillArea(); -} - -void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); - separator->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default); - groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - groupWidget->setCaption(label); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -MyGUI::TextBox* ReviewDialog::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - MyGUI::TextBox* skillValueWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -void ReviewDialog::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); - } - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) - { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); - - for (int i=0; i<2; ++i) + Widgets::MWAttributePtr attribute; + for (int idx = 0; idx < ESM::Attribute::Length; ++idx) { - ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size()-1-i], skillId); + getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); + mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); + attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); + attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0)); } - mSkillWidgetMap[skillId] = widget; - } -} + // Setup skills + getWidget(mSkillView, "SkillView"); + mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); -void ReviewDialog::updateSkillArea() -{ - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (int i = 0; i < ESM::Skill::Length; ++i) + { + mSkillValues.insert(std::make_pair(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); + } + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); + } + + void ReviewDialog::open() { - MyGUI::Gui::getInstance().destroyWidget(*it); + WindowModal::open(); + updateSkillArea(); } - mSkillWidgets.clear(); - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + void ReviewDialog::setPlayerName(const std::string &name) + { + mNameWidget->setCaption(name); + } - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + void ReviewDialog::setRace(const std::string &raceId) + { + mRaceId = raceId; - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().search(mRaceId); + if (race) + { + ToolTips::createRaceToolTip(mRaceWidget, race); + mRaceWidget->setCaption(race->mName); + } + } - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + void ReviewDialog::setClass(const ESM::Class& class_) + { + mKlass = class_; + mClassWidget->setCaption(mKlass.mName); + ToolTips::createClassToolTip(mClassWidget, mKlass); + } - mClientHeight = coord1.top; + void ReviewDialog::setBirthSign(const std::string& signId) + { + mBirthSignId = signId; + + const ESM::BirthSign *sign = + MWBase::Environment::get().getWorld()->getStore().get().search(mBirthSignId); + if (sign) + { + mBirthSignWidget->setCaption(sign->mName); + ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); + } + } + + void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) + { + mHealth->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + + void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) + { + mMagicka->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + + void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) + { + mFatigue->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } + + void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) + { + std::map::iterator attr = mAttributeWidgets.find(static_cast(attributeId)); + if (attr == mAttributeWidgets.end()) + return; + + attr->second->setAttributeValue(value); + } + + void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value) + { + mSkillValues[skillId] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + + widget->setCaption(text); + widget->_setWidgetState(state); + } + + } + + void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) + { + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } + + updateSkillArea(); + } + + void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); + separator->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); + } + + void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + groupWidget->setCaption(label); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + MyGUI::TextBox* ReviewDialog::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* skillNameWidget; + MyGUI::TextBox* skillValueWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; + } + + void ReviewDialog::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size()-1-i], skillId); + } + + mSkillWidgetMap[skillId] = widget; + } + } + + void ReviewDialog::updateSkillArea() + { + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); + } + + // widget controls + + void ReviewDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); + } + + void ReviewDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void ReviewDialog::onNameClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(NAME_DIALOG); + } + + void ReviewDialog::onRaceClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(RACE_DIALOG); + } + + void ReviewDialog::onClassClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(CLASS_DIALOG); + } + + void ReviewDialog::onBirthSignClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(BIRTHSIGN_DIALOG); + } + + void ReviewDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + } - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -// widget controls - -void ReviewDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); -} - -void ReviewDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void ReviewDialog::onNameClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(NAME_DIALOG); -} - -void ReviewDialog::onRaceClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(RACE_DIALOG); -} - -void ReviewDialog::onClassClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(CLASS_DIALOG); -} - -void ReviewDialog::onBirthSignClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(BIRTHSIGN_DIALOG); -} - -void ReviewDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 1935f7a9b6..95bf17635f 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -10,71 +10,73 @@ #include "formatting.hpp" -using namespace MWGui; - -ScrollWindow::ScrollWindow () - : WindowBase("openmw_scroll.layout") - , mTakeButtonShow(true) - , mTakeButtonAllowed(true) +namespace MWGui { - getWidget(mTextView, "TextView"); - getWidget(mCloseButton, "CloseButton"); - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); + ScrollWindow::ScrollWindow () + : WindowBase("openmw_scroll.layout") + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) + { + getWidget(mTextView, "TextView"); - getWidget(mTakeButton, "TakeButton"); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); + getWidget(mCloseButton, "CloseButton"); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); - center(); -} - -void ScrollWindow::open (MWWorld::Ptr scroll) -{ - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - - mScroll = scroll; - - MWWorld::LiveCellRef *ref = mScroll.get(); - - BookTextParser parser; - MyGUI::IntSize size = parser.parse(ref->mBase->mText, mTextView, 390); - - if (size.height > mTextView->getSize().height) - mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); - else - mTextView->setCanvasSize(410, mTextView->getSize().height); - - mTextView->setViewOffset(MyGUI::IntPoint(0,0)); - - setTakeButtonShow(true); -} - -void ScrollWindow::setTakeButtonShow(bool show) -{ - mTakeButtonShow = show; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void ScrollWindow::setInventoryAllowed(bool allowed) -{ - mTakeButtonAllowed = allowed; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); -} - -void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); - - MWWorld::ActionTake take(mScroll); - take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + getWidget(mTakeButton, "TakeButton"); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); + + center(); + } + + void ScrollWindow::open (MWWorld::Ptr scroll) + { + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); + + mScroll = scroll; + + MWWorld::LiveCellRef *ref = mScroll.get(); + + BookTextParser parser; + MyGUI::IntSize size = parser.parse(ref->mBase->mText, mTextView, 390); + + if (size.height > mTextView->getSize().height) + mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); + else + mTextView->setCanvasSize(410, mTextView->getSize().height); + + mTextView->setViewOffset(MyGUI::IntPoint(0,0)); + + setTakeButtonShow(true); + } + + void ScrollWindow::setTakeButtonShow(bool show) + { + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void ScrollWindow::setInventoryAllowed(bool allowed) + { + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + } + + void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); + + MWWorld::ActionTake take(mScroll); + take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 3439ff31ce..1134767f14 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -13,562 +13,565 @@ #include "tooltips.hpp" -using namespace MWGui; -const int StatsWindow::sLineHeight = 18; - -StatsWindow::StatsWindow () - : WindowPinnableBase("openmw_stats_window.layout") - , mSkillView(NULL) - , mClientHeight(0) - , mMajorSkills() - , mMinorSkills() - , mMiscSkills() - , mSkillValues() - , mSkillWidgetMap() - , mFactionWidgetMap() - , mFactions() - , mBirthSignId() - , mReputation(0) - , mBounty(0) - , mSkillWidgets() - , mChanged(true) +namespace MWGui { - setCoord(0,0,498, 342); - const char *names[][2] = + const int StatsWindow::sLineHeight = 18; + + StatsWindow::StatsWindow () + : WindowPinnableBase("openmw_stats_window.layout") + , mSkillView(NULL) + , mClientHeight(0) + , mMajorSkills() + , mMinorSkills() + , mMiscSkills() + , mSkillValues() + , mSkillWidgetMap() + , mFactionWidgetMap() + , mFactions() + , mBirthSignId() + , mReputation(0) + , mBounty(0) + , mSkillWidgets() + , mChanged(true) { - { "Attrib1", "sAttributeStrength" }, - { "Attrib2", "sAttributeIntelligence" }, - { "Attrib3", "sAttributeWillpower" }, - { "Attrib4", "sAttributeAgility" }, - { "Attrib5", "sAttributeSpeed" }, - { "Attrib6", "sAttributeEndurance" }, - { "Attrib7", "sAttributePersonality" }, - { "Attrib8", "sAttributeLuck" }, - { 0, 0 } - }; + setCoord(0,0,498, 342); - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for (int i=0; names[i][0]; ++i) - { - setText (names[i][0], store.get().find (names[i][1])->getString()); - } - - getWidget(mSkillView, "SkillView"); - getWidget(mLeftPane, "LeftPane"); - getWidget(mRightPane, "RightPane"); - - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); - } - - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); -} - -void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); -} - -void StatsWindow::onWindowResize(MyGUI::Window* window) -{ - mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); - mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) -{ - MyGUI::ProgressPtr pt; - getWidget(pt, name); - pt->setProgressRange(max); - pt->setProgressPosition(val); - - std::stringstream out; - out << val << "/" << max; - setText(tname, out.str().c_str()); -} - -void StatsWindow::setPlayerName(const std::string& playerName) -{ - static_cast(mMainWidget)->setCaption(playerName); - adjustWindowCaption(); -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 - }; - - for (int i=0; ids[i]; ++i) - if (ids[i]==id) + const char *names[][2] = { - std::ostringstream valueString; - valueString << value.getModified(); - setText (id, valueString.str()); + { "Attrib1", "sAttributeStrength" }, + { "Attrib2", "sAttributeIntelligence" }, + { "Attrib3", "sAttributeWillpower" }, + { "Attrib4", "sAttributeAgility" }, + { "Attrib5", "sAttributeSpeed" }, + { "Attrib6", "sAttributeEndurance" }, + { "Attrib7", "sAttributePersonality" }, + { "Attrib8", "sAttributeLuck" }, + { 0, 0 } + }; - MyGUI::TextBox* box; - getWidget(box, id); - - if (value.getModified()>value.getBase()) - box->_setWidgetState("increased"); - else if (value.getModified()_setWidgetState("decreased"); - else - box->_setWidgetState("normal"); - - break; + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for (int i=0; names[i][0]; ++i) + { + setText (names[i][0], store.get().find (names[i][1])->getString()); } -} -void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = - { - "HBar", "MBar", "FBar", - 0 - }; + getWidget(mSkillView, "SkillView"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); - for (int i=0; ids[i]; ++i) - { - if (ids[i]==id) + for (int i = 0; i < ESM::Skill::Length; ++i) { - std::string id (ids[i]); - setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); + mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); + } - // health, magicka, fatigue tooltip - MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - if (i==0) + MyGUI::WindowPtr t = static_cast(mMainWidget); + t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); + } + + void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + } + + void StatsWindow::onWindowResize(MyGUI::Window* window) + { + mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); + mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); + } + + void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) + { + MyGUI::ProgressPtr pt; + getWidget(pt, name); + pt->setProgressRange(max); + pt->setProgressPosition(val); + + std::stringstream out; + out << val << "/" << max; + setText(tname, out.str().c_str()); + } + + void StatsWindow::setPlayerName(const std::string& playerName) + { + static_cast(mMainWidget)->setCaption(playerName); + adjustWindowCaption(); + } + + void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) + { + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + if (ids[i]==id) { - getWidget(w, "Health"); - w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + std::ostringstream valueString; + valueString << value.getModified(); + setText (id, valueString.str()); + + MyGUI::TextBox* box; + getWidget(box, id); + + if (value.getModified()>value.getBase()) + box->_setWidgetState("increased"); + else if (value.getModified()_setWidgetState("decreased"); + else + box->_setWidgetState("normal"); + + break; } - else if (i==1) + } + + void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) + { + static const char *ids[] = + { + "HBar", "MBar", "FBar", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) { - getWidget(w, "Magicka"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); - } - else if (i==2) - { - getWidget(w, "Fatigue"); - w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + std::string id (ids[i]); + setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); + + // health, magicka, fatigue tooltip + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + if (i==0) + { + getWidget(w, "Health"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + else if (i==1) + { + getWidget(w, "Magicka"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + else if (i==2) + { + getWidget(w, "Fatigue"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } } } } -} -void StatsWindow::setValue (const std::string& id, const std::string& value) -{ - if (id=="name") - setPlayerName (value); - else if (id=="race") - setText ("RaceText", value); - else if (id=="class") - setText ("ClassText", value); -} - -void StatsWindow::setValue (const std::string& id, int value) -{ - if (id=="level") + void StatsWindow::setValue (const std::string& id, const std::string& value) { - std::ostringstream text; - text << value; - setText("LevelText", text.str()); - } -} - -void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) -{ - mSkillValues[parSkill] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } -} - -void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); + if (id=="name") + setPlayerName (value); + else if (id=="race") + setText ("RaceText", value); + else if (id=="class") + setText ("ClassText", value); } - updateSkillArea(); -} - -void StatsWindow::onFrame () -{ - if (!mMainWidget->getVisible()) - return; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - - // level progress - MyGUI::Widget* levelWidget; - for (int i=0; i<2; ++i) + void StatsWindow::setValue (const std::string& id, int value) { - getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); - levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); - levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + if (id=="level") + { + std::ostringstream text; + text << value; + setText("LevelText", text.str()); + } } - setFactions(PCstats.getFactionRanks()); - setExpelled(PCstats.getExpelled ()); + void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) + { + mSkillValues[parSkill] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; - const std::string &signId = - MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + widget->setCaption(text); + widget->_setWidgetState(state); + } + } - setBirthSign(signId); - setReputation (PCstats.getReputation ()); - setBounty (PCstats.getBounty ()); + void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) + { + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } - if (mChanged) updateSkillArea(); -} - -void StatsWindow::setFactions (const FactionList& factions) -{ - if (mFactions != factions) - { - mFactions = factions; - mChanged = true; - } -} - -void StatsWindow::setExpelled (const std::set& expelled) -{ - if (mExpelled != expelled) - { - mExpelled = expelled; - mChanged = true; - } -} - -void StatsWindow::setBirthSign (const std::string& signId) -{ - if (signId != mBirthSignId) - { - mBirthSignId = signId; - mChanged = true; - } -} - -void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", - MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", - MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - groupWidget->setCaption(label); - groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox *skillNameWidget, *skillValueWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillNameWidget; -} - -void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); } - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + void StatsWindow::onFrame () { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - int progressPercent = (modified - float(static_cast(modified))) * 100; + if (!mMainWidget->getVisible()) + return; - const MWWorld::ESMStore &esmStore = - MWBase::Environment::get().getWorld()->getStore(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - const ESM::Skill* skill = esmStore.get().find(skillId); - assert(skill); + // level progress + MyGUI::Widget* levelWidget; + for (int i=0; i<2; ++i) + { + getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); + levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); + levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + } - std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + setFactions(PCstats.getFactionRanks()); + setExpelled(PCstats.getExpelled ()); - const ESM::Attribute* attr = - esmStore.get().find(skill->mData.mAttribute); - assert(attr); + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), - boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + setBirthSign(signId); + setReputation (PCstats.getReputation ()); + setBounty (PCstats.getBounty ()); + + if (mChanged) + updateSkillArea(); + } + + void StatsWindow::setFactions (const FactionList& factions) + { + if (mFactions != factions) + { + mFactions = factions; + mChanged = true; + } + } + + void StatsWindow::setExpelled (const std::set& expelled) + { + if (mExpelled != expelled) + { + mExpelled = expelled; + mChanged = true; + } + } + + void StatsWindow::setBirthSign (const std::string& signId) + { + if (signId != mBirthSignId) + { + mBirthSignId = signId; + mChanged = true; + } + } + + void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", + MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); + } + + void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", + MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + groupWidget->setCaption(label); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox *skillNameWidget, *skillValueWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; + } + + MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillNameWidget; + } + + void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + int progressPercent = (modified - float(static_cast(modified))) * 100; + + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Skill* skill = esmStore.get().find(skillId); + assert(skill); + + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + const ESM::Attribute* attr = + esmStore.get().find(skill->mData.mAttribute); + assert(attr); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), + boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + } + + mSkillWidgetMap[skillId] = widget; + } + } + + void StatsWindow::updateSkillArea() + { + mChanged = false; + + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); + mClientHeight = 0; + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::NPC *player = + world->getPlayer().getPlayer().get()->mBase; + + // race tooltip + const ESM::Race* playerRace = store.get().find(player->mRace); + + MyGUI::Widget* raceWidget; + getWidget(raceWidget, "RaceText"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + getWidget(raceWidget, "Race_str"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + + // class tooltip + MyGUI::Widget* classWidget; + + const ESM::Class *playerClass = + store.get().find(player->mClass); + + getWidget(classWidget, "ClassText"); + ToolTips::createClassToolTip(classWidget, *playerClass); + getWidget(classWidget, "Class_str"); + ToolTips::createClassToolTip(classWidget, *playerClass); + + if (!mFactions.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + std::set& expelled = PCstats.getExpelled (); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); + FactionList::const_iterator end = mFactions.end(); + for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + { + const ESM::Faction *faction = + store.get().find(it->first); + MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); + + std::string text; + + text += std::string("#DDC79E") + faction->mName; + + if (expelled.find(it->first) != expelled.end()) + text += "\n#{sExpelled}"; + else + { + text += std::string("\n#BF9959") + faction->mRanks[it->second]; + + if (it->second < 9) + { + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + + ESM::RankData rankData = faction->mData.mRankData[it->second+1]; + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.mSkill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + if (rankData.mSkill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); + } + } + + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "TextToolTip"); + w->setUserString("Caption_Text", text); + } + } + + if (!mBirthSignId.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); + const ESM::BirthSign *sign = + store.get().find(mBirthSignId); + MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); + + ToolTips::createBirthsignToolTip(w, mBirthSignId); + } + + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), + boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); } - mSkillWidgetMap[skillId] = widget; - } -} + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), + boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); -void StatsWindow::updateSkillArea() -{ - mChanged = false; - - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillWidgets.clear(); - - mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); - mClientHeight = 0; - - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); - - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); - - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); - - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - - MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::ESMStore &store = world->getStore(); - const ESM::NPC *player = - world->getPlayer().getPlayer().get()->mBase; - - // race tooltip - const ESM::Race* playerRace = store.get().find(player->mRace); - - MyGUI::Widget* raceWidget; - getWidget(raceWidget, "RaceText"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - getWidget(raceWidget, "Race_str"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - - // class tooltip - MyGUI::Widget* classWidget; - - const ESM::Class *playerClass = - store.get().find(player->mClass); - - getWidget(classWidget, "ClassText"); - ToolTips::createClassToolTip(classWidget, *playerClass); - getWidget(classWidget, "Class_str"); - ToolTips::createClassToolTip(classWidget, *playerClass); - - if (!mFactions.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - std::set& expelled = PCstats.getExpelled (); - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); - FactionList::const_iterator end = mFactions.end(); - for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + for (int i=0; i<2; ++i) { - const ESM::Faction *faction = - store.get().find(it->first); - MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); - - std::string text; - - text += std::string("#DDC79E") + faction->mName; - - if (expelled.find(it->first) != expelled.end()) - text += "\n#{sExpelled}"; - else - { - text += std::string("\n#BF9959") + faction->mRanks[it->second]; - - if (it->second < 9) - { - // player doesn't have max rank yet - text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; - - ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - assert(attr1 && attr2); - - text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); - - text += "\n\n#DDC79E#{sFavoriteSkills}"; - text += "\n#BF9959"; - for (int i=0; i<6; ++i) - { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; - if (i<5) - text += ", "; - } - - text += "\n"; - - if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); - if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); - } - } - - w->setUserString("ToolTipType", "Layout"); - w->setUserString("ToolTipLayout", "TextToolTip"); - w->setUserString("Caption_Text", text); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); } + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); } - if (!mBirthSignId.empty()) + void StatsWindow::onPinToggled() { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); - const ESM::BirthSign *sign = - store.get().find(mBirthSignId); - MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); - - ToolTips::createBirthsignToolTip(w, mBirthSignId); + MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); } - - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); - } - - addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); - } - - mClientHeight = coord1.top; - - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::onPinToggled() -{ - MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); } diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index ab2936cfce..d4f8a25336 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -3,68 +3,71 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" -using namespace MWGui; - -TextInputDialog::TextInputDialog() - : WindowModal("openmw_text_input.layout") +namespace MWGui { - // Centre dialog - center(); - getWidget(mTextEdit, "TextEdit"); - mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -void TextInputDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -void TextInputDialog::setTextLabel(const std::string &label) -{ - setText("LabelT", label); -} - -void TextInputDialog::open() -{ - WindowModal::open(); - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -// widget controls - -void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if (mTextEdit->getCaption() == "") + TextInputDialog::TextInputDialog() + : WindowModal("openmw_text_input.layout") { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} + // Centre dialog + center(); -void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) -{ - if (mTextEdit->getCaption() == "") - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + getWidget(mTextEdit, "TextEdit"); + mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); } - else - eventDone(this); + + void TextInputDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void TextInputDialog::setTextLabel(const std::string &label) + { + setText("LabelT", label); + } + + void TextInputDialog::open() + { + WindowModal::open(); + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + } + + // widget controls + + void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) + { + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); + } + + void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) + { + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); + } + } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index b72d27aeae..d86aa69412 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -9,761 +9,763 @@ #include "mapwindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; -using namespace MyGUI; - -ToolTips::ToolTips() : - Layout("openmw_tooltips.layout") - , mGameMode(true) - , mFullHelp(false) - , mEnabled(true) - , mFocusToolTipX(0.0) - , mFocusToolTipY(0.0) - , mDelay(0.0) - , mRemainingDelay(0.0) - , mLastMouseX(0) - , mLastMouseY(0) - , mHorizontalScrollIndex(0) -{ - getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); - - mDynamicToolTipBox->setVisible(false); - - // turn off mouse focus so that getMouseFocusWidget returns the correct widget, - // even if the mouse is over the tooltip - mDynamicToolTipBox->setNeedMouseFocus(false); - mMainWidget->setNeedMouseFocus(false); - - mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); - mRemainingDelay = mDelay; - - for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) - { - mMainWidget->getChildAt(i)->setVisible(false); - } -} - -void ToolTips::setEnabled(bool enabled) -{ - mEnabled = enabled; -} - -void ToolTips::onFrame(float frameDuration) +namespace MWGui { - while (mDynamicToolTipBox->getChildCount()) + ToolTips::ToolTips() : + Layout("openmw_tooltips.layout") + , mGameMode(true) + , mFullHelp(false) + , mEnabled(true) + , mFocusToolTipX(0.0) + , mFocusToolTipY(0.0) + , mDelay(0.0) + , mRemainingDelay(0.0) + , mLastMouseX(0) + , mLastMouseY(0) + , mHorizontalScrollIndex(0) { - MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); - } + getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); - // start by hiding everything - for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) - { - mMainWidget->getChildAt(i)->setVisible(false); - } + mDynamicToolTipBox->setVisible(false); - const IntSize &viewSize = RenderManager::getInstance().getViewSize(); + // turn off mouse focus so that getMouseFocusWidget returns the correct widget, + // even if the mouse is over the tooltip + mDynamicToolTipBox->setNeedMouseFocus(false); + mMainWidget->setNeedMouseFocus(false); - if (!mEnabled) - { - return; - } + mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); + mRemainingDelay = mDelay; - if (!mGameMode) - { - const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - - if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) - || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) - || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) { - mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); + mMainWidget->getChildAt(i)->setVisible(false); + } + } - if (mFocusObject.isEmpty ()) - return; + void ToolTips::setEnabled(bool enabled) + { + mEnabled = enabled; + } - const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + void ToolTips::onFrame(float frameDuration) + { - IntSize tooltipSize; - if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) - { - setCoord(0, 0, 300, 300); - mDynamicToolTipBox->setVisible(true); - ToolTipInfo info; - info.caption=mFocusObject.getCellRef().mRefID; - info.icon=""; - tooltipSize = createToolTip(info); - } - else - tooltipSize = getToolTipViaPtr(true); - - IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - - // make the tooltip stay completely in the viewport - if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) - { - tooltipPosition.left = viewSize.width - tooltipSize.width; - } - if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) - { - tooltipPosition.top = viewSize.height - tooltipSize.height; - } - - setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + while (mDynamicToolTipBox->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); } + // start by hiding everything + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) + { + mMainWidget->getChildAt(i)->setVisible(false); + } + + const MyGUI::IntSize &viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + if (!mEnabled) + { + return; + } + + if (!mGameMode) + { + const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); + + if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) + { + mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); + + if (mFocusObject.isEmpty ()) + return; + + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + + MyGUI::IntSize tooltipSize; + if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=mFocusObject.getCellRef().mRefID; + info.icon=""; + tooltipSize = createToolTip(info); + } + else + tooltipSize = getToolTipViaPtr(true); + + MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition() + MyGUI::IntPoint(0, 24); + + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - tooltipSize.width; + } + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - tooltipSize.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + } + + else + { + const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + + if (mousePos == lastPressed) // mouseclick makes tooltip disappear + return; + + if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) + { + mRemainingDelay -= frameDuration; + } + else + { + mHorizontalScrollIndex = 0; + mRemainingDelay = mDelay; + } + mLastMouseX = mousePos.left; + mLastMouseY = mousePos.top; + + + if (mRemainingDelay > 0) + return; + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget(); + if (focus == 0) + return; + + MyGUI::IntSize tooltipSize; + + // try to go 1 level up until there is a widget that has tooltip + // this is necessary because some skin elements are actually separate widgets + int i=0; + while (!focus->isUserString("ToolTipType")) + { + focus = focus->getParent(); + if (!focus) + return; + ++i; + } + + std::string type = focus->getUserString("ToolTipType"); + std::string text = focus->getUserString("ToolTipText"); + + if (type == "") + { + return; + } + + + // special handling for markers on the local map: the tooltip should only be visible + // if the marker is not hidden due to the fog of war. + if (focus->getUserString ("IsMarker") == "true") + { + LocalMapBase::MarkerPosition pos = *focus->getUserData(); + + if (!MWBase::Environment::get().getWorld ()->isPositionExplored (pos.nX, pos.nY, pos.cellX, pos.cellY, pos.interior)) + return; + } + + if (type == "ItemPtr") + { + mFocusObject = *focus->getUserData(); + tooltipSize = getToolTipViaPtr(false); + } + else if (type == "ToolTipInfo") + { + tooltipSize = createToolTip(*focus->getUserData()); + } + else if (type == "AvatarItemSelection") + { + MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); + MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); + int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); + int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); + MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + + mFocusObject = item; + if (!mFocusObject.isEmpty ()) + tooltipSize = getToolTipViaPtr(false); + } + else if (type == "Spell") + { + ToolTipInfo info; + + const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); + info.caption = spell->mName; + Widgets::SpellEffectList effects; + std::vector::const_iterator end = spell->mEffects.mList.end(); + for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + { + Widgets::SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + params.mIsConstant = (spell->mData.mType == ESM::Spell::ST_Ability); + params.mNoTarget = false; + effects.push_back(params); + } + info.effects = effects; + tooltipSize = createToolTip(info); + } + else if (type == "Layout") + { + // tooltip defined in the layout + MyGUI::Widget* tooltip; + getWidget(tooltip, focus->getUserString("ToolTipLayout")); + + tooltip->setVisible(true); + + std::map userStrings = focus->getUserStrings(); + for (std::map::iterator it = userStrings.begin(); + it != userStrings.end(); ++it) + { + if (it->first == "ToolTipType" + || it->first == "ToolTipLayout" + || it->first == "IsMarker") + continue; + + + size_t underscorePos = it->first.find("_"); + std::string propertyKey = it->first.substr(0, underscorePos); + std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); + + MyGUI::Widget* w; + getWidget(w, widgetName); + w->setProperty(propertyKey, it->second); + } + + tooltipSize = tooltip->getSize(); + + tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); + } + else + throw std::runtime_error ("unknown tooltip type"); + + MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition() + MyGUI::IntPoint(0, 24); + + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - tooltipSize.width; + } + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - tooltipSize.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + } + } else { - const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); - - if (mousePos == lastPressed) // mouseclick makes tooltip disappear - return; - - if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) + if (!mFocusObject.isEmpty()) { - mRemainingDelay -= frameDuration; + MyGUI::IntSize tooltipSize = getToolTipViaPtr(); + + setCoord(viewSize.width/2 - tooltipSize.width/2, + std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), + tooltipSize.width, + tooltipSize.height); + + mDynamicToolTipBox->setVisible(true); } - else - { - mHorizontalScrollIndex = 0; - mRemainingDelay = mDelay; - } - mLastMouseX = mousePos.left; - mLastMouseY = mousePos.top; - - - if (mRemainingDelay > 0) - return; - - Widget* focus = InputManager::getInstance().getMouseFocusWidget(); - if (focus == 0) - return; - - IntSize tooltipSize; - - // try to go 1 level up until there is a widget that has tooltip - // this is necessary because some skin elements are actually separate widgets - int i=0; - while (!focus->isUserString("ToolTipType")) - { - focus = focus->getParent(); - if (!focus) - return; - ++i; - } - - std::string type = focus->getUserString("ToolTipType"); - std::string text = focus->getUserString("ToolTipText"); - - if (type == "") - { - return; - } - - - // special handling for markers on the local map: the tooltip should only be visible - // if the marker is not hidden due to the fog of war. - if (focus->getUserString ("IsMarker") == "true") - { - LocalMapBase::MarkerPosition pos = *focus->getUserData(); - - if (!MWBase::Environment::get().getWorld ()->isPositionExplored (pos.nX, pos.nY, pos.cellX, pos.cellY, pos.interior)) - return; - } - - if (type == "ItemPtr") - { - mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(false); - } - else if (type == "ToolTipInfo") - { - tooltipSize = createToolTip(*focus->getUserData()); - } - else if (type == "AvatarItemSelection") - { - MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); - MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); - int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); - int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); - MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); - - mFocusObject = item; - if (!mFocusObject.isEmpty ()) - tooltipSize = getToolTipViaPtr(false); - } - else if (type == "Spell") - { - ToolTipInfo info; - - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); - info.caption = spell->mName; - Widgets::SpellEffectList effects; - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) - { - Widgets::SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mIsConstant = (spell->mData.mType == ESM::Spell::ST_Ability); - params.mNoTarget = false; - effects.push_back(params); - } - info.effects = effects; - tooltipSize = createToolTip(info); - } - else if (type == "Layout") - { - // tooltip defined in the layout - MyGUI::Widget* tooltip; - getWidget(tooltip, focus->getUserString("ToolTipLayout")); - - tooltip->setVisible(true); - - std::map userStrings = focus->getUserStrings(); - for (std::map::iterator it = userStrings.begin(); - it != userStrings.end(); ++it) - { - if (it->first == "ToolTipType" - || it->first == "ToolTipLayout" - || it->first == "IsMarker") - continue; - - - size_t underscorePos = it->first.find("_"); - std::string propertyKey = it->first.substr(0, underscorePos); - std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); - - MyGUI::Widget* w; - getWidget(w, widgetName); - w->setProperty(propertyKey, it->second); - } - - tooltipSize = tooltip->getSize(); - - tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); - } - else - throw std::runtime_error ("unknown tooltip type"); - - IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - - // make the tooltip stay completely in the viewport - if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) - { - tooltipPosition.left = viewSize.width - tooltipSize.width; - } - if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) - { - tooltipPosition.top = viewSize.height - tooltipSize.height; - } - - setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); } } - else + + void ToolTips::enterGameMode() { - if (!mFocusObject.isEmpty()) + mGameMode = true; + } + + void ToolTips::enterGuiMode() + { + mGameMode = false; + } + + void ToolTips::setFocusObject(const MWWorld::Ptr& focus) + { + mFocusObject = focus; + } + + MyGUI::IntSize ToolTips::getToolTipViaPtr (bool image) + { + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + MyGUI::IntSize tooltipSize; + + const MWWorld::Class& object = MWWorld::Class::get (mFocusObject); + if (!object.hasToolTip(mFocusObject)) + { + mDynamicToolTipBox->setVisible(false); + } + else { - IntSize tooltipSize = getToolTipViaPtr(); - - setCoord(viewSize.width/2 - tooltipSize.width/2, - std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), - tooltipSize.width, - tooltipSize.height); - mDynamicToolTipBox->setVisible(true); + + ToolTipInfo info = object.getToolTipInfo(mFocusObject); + if (!image) + info.icon = ""; + tooltipSize = createToolTip(info); + } + + return tooltipSize; + } + + void ToolTips::findImageExtension(std::string& image) + { + int len = image.size(); + if (len < 4) return; + + if (!Ogre::ResourceGroupManager::getSingleton().resourceExists(Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, image)) + { + // Change texture extension to .dds + image[len-3] = 'd'; + image[len-2] = 'd'; + image[len-1] = 's'; } } -} -void ToolTips::enterGameMode() -{ - mGameMode = true; -} - -void ToolTips::enterGuiMode() -{ - mGameMode = false; -} - -void ToolTips::setFocusObject(const MWWorld::Ptr& focus) -{ - mFocusObject = focus; -} - -IntSize ToolTips::getToolTipViaPtr (bool image) -{ - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); - - IntSize tooltipSize; - - const MWWorld::Class& object = MWWorld::Class::get (mFocusObject); - if (!object.hasToolTip(mFocusObject)) - { - mDynamicToolTipBox->setVisible(false); - } - else + MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { mDynamicToolTipBox->setVisible(true); - ToolTipInfo info = object.getToolTipInfo(mFocusObject); - if (!image) - info.icon = ""; - tooltipSize = createToolTip(info); - } + std::string caption = info.caption; + std::string image = info.icon; + int imageSize = (image != "") ? info.imageSize : 0; + std::string text = info.text; - return tooltipSize; -} + // remove the first newline (easier this way) + if (text.size() > 0 && text[0] == '\n') + text.erase(0, 1); -void ToolTips::findImageExtension(std::string& image) -{ - int len = image.size(); - if (len < 4) return; + if(caption.size() > 0 && isalnum(caption[0])) + caption[0] = toupper(caption[0]); - if (!Ogre::ResourceGroupManager::getSingleton().resourceExists(Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, image)) - { - // Change texture extension to .dds - image[len-3] = 'd'; - image[len-2] = 'd'; - image[len-1] = 's'; - } -} - -IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) -{ - mDynamicToolTipBox->setVisible(true); - - std::string caption = info.caption; - std::string image = info.icon; - int imageSize = (image != "") ? info.imageSize : 0; - std::string text = info.text; - - // remove the first newline (easier this way) - if (text.size() > 0 && text[0] == '\n') - text.erase(0, 1); - - if(caption.size() > 0 && isalnum(caption[0])) - caption[0] = toupper(caption[0]); - - const ESM::Enchantment* enchant = 0; - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - if (info.enchant != "") - { - enchant = store.get().find(info.enchant); - if (enchant->mData.mType == ESM::Enchantment::CastOnce) - text += "\n#{sItemCastOnce}"; - else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) - text += "\n#{sItemCastWhenStrikes}"; - else if (enchant->mData.mType == ESM::Enchantment::WhenUsed) - text += "\n#{sItemCastWhenUsed}"; - else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) - text += "\n#{sItemCastConstant}"; - } - - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); - - const IntPoint padding(8, 8); - - const int maximumWidth = 500; - - const int imageCaptionHPadding = (caption != "" ? 8 : 0); - const int imageCaptionVPadding = (caption != "" ? 4 : 0); - - std::string realImage = "icons\\" + image; - findImageExtension(realImage); - - EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption"); - captionWidget->setProperty("Static", "true"); - captionWidget->setCaptionWithReplacing(caption); - IntSize captionSize = captionWidget->getTextSize(); - - int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); - - EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), Align::Stretch, "ToolTipText"); - textWidget->setProperty("Static", "true"); - textWidget->setProperty("MultiLine", "true"); - textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); - textWidget->setCaptionWithReplacing(text); - textWidget->setTextAlign(Align::HCenter | Align::Top); - IntSize textSize = textWidget->getTextSize(); - - captionSize += IntSize(imageSize, 0); // adjust for image - IntSize totalSize = IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), - ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - - if (!info.effects.empty()) - { - Widget* effectArea = mDynamicToolTipBox->createWidget("", - IntCoord(0, totalSize.height, 300, 300-totalSize.height), - Align::Stretch, "ToolTipEffectArea"); - - IntCoord coord(0, 6, totalSize.width, 24); - - /** - * \todo - * the various potion effects should appear in the tooltip depending if the player - * has enough skill in alchemy to know about the effects of this potion. - */ - - Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget - ("MW_StatName", coord, Align::Default, "ToolTipEffectsWidget"); - effectsWidget->setEffectList(info.effects); - - std::vector effectItems; - effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, info.isPotion ? Widgets::MWEffectList::EF_NoTarget : 0); - totalSize.height += coord.top-6; - totalSize.width = std::max(totalSize.width, coord.width); - } - - if (info.enchant != "") - { - assert(enchant); - Widget* enchantArea = mDynamicToolTipBox->createWidget("", - IntCoord(0, totalSize.height, 300, 300-totalSize.height), - Align::Stretch, "ToolTipEnchantArea"); - - IntCoord coord(0, 6, totalSize.width, 24); - - Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget - ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); - enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); - - std::vector enchantEffectItems; - int flag = (enchant->mData.mType == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; - enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, flag); - totalSize.height += coord.top-6; - totalSize.width = std::max(totalSize.width, coord.width); - - if (enchant->mData.mType == ESM::Enchantment::WhenStrikes - || enchant->mData.mType == ESM::Enchantment::WhenUsed) + const ESM::Enchantment* enchant = 0; + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + if (info.enchant != "") { - int maxCharge = enchant->mData.mCharge; - int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; - - const int chargeWidth = 204; - - TextBox* chargeText = enchantArea->createWidget("SandText", IntCoord(0, 0, 10, 18), Align::Default, "ToolTipEnchantChargeText"); - chargeText->setCaptionWithReplacing("#{sCharges}"); - - const int chargeTextWidth = chargeText->getTextSize().width + 5; - - const int chargeAndTextWidth = chargeWidth + chargeTextWidth; - - totalSize.width = std::max(totalSize.width, chargeAndTextWidth); - - chargeText->setCoord((totalSize.width - chargeAndTextWidth)/2, coord.top+6, chargeTextWidth, 18); - - IntCoord chargeCoord; - if (totalSize.width < chargeWidth) - { - totalSize.width = chargeWidth; - chargeCoord = IntCoord(0, coord.top+6, chargeWidth, 18); - } - else - { - chargeCoord = IntCoord((totalSize.width - chargeAndTextWidth)/2 + chargeTextWidth, coord.top+6, chargeWidth, 18); - } - Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget - ("MW_ChargeBar", chargeCoord, Align::Default, "ToolTipEnchantCharge"); - chargeWidget->setValue(charge, charge); - totalSize.height += 24; + enchant = store.get().find(info.enchant); + if (enchant->mData.mType == ESM::Enchantment::CastOnce) + text += "\n#{sItemCastOnce}"; + else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) + text += "\n#{sItemCastWhenStrikes}"; + else if (enchant->mData.mType == ESM::Enchantment::WhenUsed) + text += "\n#{sItemCastWhenUsed}"; + else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) + text += "\n#{sItemCastConstant}"; } - } - captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, - (captionHeight-captionSize.height)/2, - captionSize.width-imageSize, - captionSize.height); + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); - //if its too long we do hscroll with the caption - if (captionSize.width > maximumWidth) - { - mHorizontalScrollIndex = mHorizontalScrollIndex + 2; - if (mHorizontalScrollIndex > captionSize.width){ - mHorizontalScrollIndex = -totalSize.width; - } - int horizontal_scroll = mHorizontalScrollIndex; - if (horizontal_scroll < 40){ - horizontal_scroll = 40; - }else{ - horizontal_scroll = 80 - mHorizontalScrollIndex; - } - captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); - } else { - captionWidget->setPosition (captionWidget->getPosition() + padding); - } + const MyGUI::IntPoint padding(8, 8); - textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + const int maximumWidth = 500; - if (image != "") - { - ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", - IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), - Align::Left | Align::Top, "ToolTipImage"); - imageWidget->setImageTexture(realImage); - imageWidget->setPosition (imageWidget->getPosition() + padding); - } + const int imageCaptionHPadding = (caption != "" ? 8 : 0); + const int imageCaptionVPadding = (caption != "" ? 4 : 0); - totalSize += IntSize(padding.left*2, padding.top*2); + std::string realImage = "icons\\" + image; + findImageExtension(realImage); - return totalSize; -} + MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); + captionWidget->setProperty("Static", "true"); + captionWidget->setCaptionWithReplacing(caption); + MyGUI::IntSize captionSize = captionWidget->getTextSize(); -std::string ToolTips::toString(const float value) -{ - std::ostringstream stream; - stream << std::setprecision(3) << value; - return stream.str(); -} + int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); -std::string ToolTips::toString(const int value) -{ - std::ostringstream stream; - stream << value; - return stream.str(); -} + MyGUI::EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), MyGUI::Align::Stretch, "ToolTipText"); + textWidget->setProperty("Static", "true"); + textWidget->setProperty("MultiLine", "true"); + textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); + textWidget->setCaptionWithReplacing(text); + textWidget->setTextAlign(MyGUI::Align::HCenter | MyGUI::Align::Top); + MyGUI::IntSize textSize = textWidget->getTextSize(); -std::string ToolTips::getValueString(const int value, const std::string& prefix) -{ - if (value == 0) - return ""; - else - return "\n" + prefix + ": " + toString(value); -} + captionSize += MyGUI::IntSize(imageSize, 0); // adjust for image + MyGUI::IntSize totalSize = MyGUI::IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), + ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); -std::string ToolTips::getMiscString(const std::string& text, const std::string& prefix) -{ - if (text == "") - return ""; - else - return "\n" + prefix + ": " + text; -} - -std::string ToolTips::getCountString(const int value) -{ - if (value == 1) - return ""; - else - return " (" + boost::lexical_cast(value) + ")"; -} - -void ToolTips::toggleFullHelp() -{ - mFullHelp = !mFullHelp; -} - -bool ToolTips::getFullHelp() const -{ - return mFullHelp; -} - -void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) -{ - mFocusToolTipX = (min_x + max_x) / 2; - mFocusToolTipY = min_y; -} - -void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId) -{ - if (skillId == -1) - return; - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const ESM::Skill* skill = store.get().find(skillId); - assert(skill); - - const ESM::Attribute* attr = - store.get().find(skill->mData.mAttribute); - assert(attr); - std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip"); - widget->setUserString("Caption_SkillNoProgressName", "#{"+skillNameId+"}"); - widget->setUserString("Caption_SkillNoProgressDescription", skill->mDescription); - widget->setUserString("Caption_SkillNoProgressAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - widget->setUserString("ImageTexture_SkillNoProgressImage", icon); -} - -void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId) -{ - if (attributeId == -1) - return; - - std::string icon = ESM::Attribute::sAttributeIcons[attributeId]; - std::string name = ESM::Attribute::sGmstAttributeIds[attributeId]; - std::string desc = ESM::Attribute::sGmstAttributeDescIds[attributeId]; - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", "#{"+name+"}"); - widget->setUserString("Caption_AttributeDescription", "#{"+desc+"}"); - widget->setUserString("ImageTexture_AttributeImage", icon); -} - -void ToolTips::createSpecializationToolTip(MyGUI::Widget* widget, const std::string& name, int specId) -{ - widget->setUserString("Caption_CenteredCaption", name); - std::string specText; - // get all skills of this specialisation - const MWWorld::Store &skills = - MWBase::Environment::get().getWorld()->getStore().get(); - - MWWorld::Store::iterator it = skills.begin(); - for (; it != skills.end(); ++it) - { - if (it->mData.mSpecialization == specId) - specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->mIndex] + "}"; - } - widget->setUserString("Caption_CenteredCaptionText", specText); - widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); - widget->setUserString("ToolTipType", "Layout"); -} - -void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId) -{ - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::BirthSign *sign = store.get().find(birthsignId); - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "BirthSignToolTip"); - std::string image = sign->mTexture; - image.replace(image.size()-3, 3, "dds"); - widget->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); - std::string text; - - text += sign->mName; - text += "\n#BF9959" + sign->mDescription; - - std::vector abilities, powers, spells; - - std::vector::const_iterator it = sign->mPowers.mList.begin(); - std::vector::const_iterator end = sign->mPowers.mList.end(); - for (; it != end; ++it) - { - const std::string &spellId = *it; - const ESM::Spell *spell = store.get().search(spellId); - if (!spell) - continue; // Skip spells which cannot be found - ESM::Spell::SpellType type = static_cast(spell->mData.mType); - if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) - continue; // We only want spell, ability and powers. - - if (type == ESM::Spell::ST_Ability) - abilities.push_back(spellId); - else if (type == ESM::Spell::ST_Power) - powers.push_back(spellId); - else if (type == ESM::Spell::ST_Spell) - spells.push_back(spellId); - } - - struct { - const std::vector &spells; - std::string label; - } - categories[3] = { - {abilities, "sBirthsignmenu1"}, - {powers, "sPowers"}, - {spells, "sBirthsignmenu2"} - }; - - for (int category = 0; category < 3; ++category) - { - for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + if (!info.effects.empty()) { - if (it == categories[category].spells.begin()) - { - text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; - } + MyGUI::Widget* effectArea = mDynamicToolTipBox->createWidget("", + MyGUI::IntCoord(0, totalSize.height, 300, 300-totalSize.height), + MyGUI::Align::Stretch, "ToolTipEffectArea"); + MyGUI::IntCoord coord(0, 6, totalSize.width, 24); + + /** + * \todo + * the various potion effects should appear in the tooltip depending if the player + * has enough skill in alchemy to know about the effects of this potion. + */ + + Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget + ("MW_StatName", coord, MyGUI::Align::Default, "ToolTipEffectsWidget"); + effectsWidget->setEffectList(info.effects); + + std::vector effectItems; + effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, info.isPotion ? Widgets::MWEffectList::EF_NoTarget : 0); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + } + + if (info.enchant != "") + { + assert(enchant); + MyGUI::Widget* enchantArea = mDynamicToolTipBox->createWidget("", + MyGUI::IntCoord(0, totalSize.height, 300, 300-totalSize.height), + MyGUI::Align::Stretch, "ToolTipEnchantArea"); + + MyGUI::IntCoord coord(0, 6, totalSize.width, 24); + + Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget + ("MW_StatName", coord, MyGUI::Align::Default, "ToolTipEnchantWidget"); + enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); + + std::vector enchantEffectItems; + int flag = (enchant->mData.mType == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; + enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, flag); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + + if (enchant->mData.mType == ESM::Enchantment::WhenStrikes + || enchant->mData.mType == ESM::Enchantment::WhenUsed) + { + int maxCharge = enchant->mData.mCharge; + int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; + + const int chargeWidth = 204; + + MyGUI::TextBox* chargeText = enchantArea->createWidget("SandText", MyGUI::IntCoord(0, 0, 10, 18), MyGUI::Align::Default, "ToolTipEnchantChargeText"); + chargeText->setCaptionWithReplacing("#{sCharges}"); + + const int chargeTextWidth = chargeText->getTextSize().width + 5; + + const int chargeAndTextWidth = chargeWidth + chargeTextWidth; + + totalSize.width = std::max(totalSize.width, chargeAndTextWidth); + + chargeText->setCoord((totalSize.width - chargeAndTextWidth)/2, coord.top+6, chargeTextWidth, 18); + + MyGUI::IntCoord chargeCoord; + if (totalSize.width < chargeWidth) + { + totalSize.width = chargeWidth; + chargeCoord = MyGUI::IntCoord(0, coord.top+6, chargeWidth, 18); + } + else + { + chargeCoord = MyGUI::IntCoord((totalSize.width - chargeAndTextWidth)/2 + chargeTextWidth, coord.top+6, chargeWidth, 18); + } + Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget + ("MW_ChargeBar", chargeCoord, MyGUI::Align::Default, "ToolTipEnchantCharge"); + chargeWidget->setValue(charge, charge); + totalSize.height += 24; + } + } + + captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, + (captionHeight-captionSize.height)/2, + captionSize.width-imageSize, + captionSize.height); + + //if its too long we do hscroll with the caption + if (captionSize.width > maximumWidth) + { + mHorizontalScrollIndex = mHorizontalScrollIndex + 2; + if (mHorizontalScrollIndex > captionSize.width){ + mHorizontalScrollIndex = -totalSize.width; + } + int horizontal_scroll = mHorizontalScrollIndex; + if (horizontal_scroll < 40){ + horizontal_scroll = 40; + }else{ + horizontal_scroll = 80 - mHorizontalScrollIndex; + } + captionWidget->setPosition (MyGUI::IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); + } else { + captionWidget->setPosition (captionWidget->getPosition() + padding); + } + + textWidget->setPosition (textWidget->getPosition() + MyGUI::IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + + if (image != "") + { + MyGUI::ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", + MyGUI::IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), + MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipImage"); + imageWidget->setImageTexture(realImage); + imageWidget->setPosition (imageWidget->getPosition() + padding); + } + + totalSize += MyGUI::IntSize(padding.left*2, padding.top*2); + + return totalSize; + } + + std::string ToolTips::toString(const float value) + { + std::ostringstream stream; + stream << std::setprecision(3) << value; + return stream.str(); + } + + std::string ToolTips::toString(const int value) + { + std::ostringstream stream; + stream << value; + return stream.str(); + } + + std::string ToolTips::getValueString(const int value, const std::string& prefix) + { + if (value == 0) + return ""; + else + return "\n" + prefix + ": " + toString(value); + } + + std::string ToolTips::getMiscString(const std::string& text, const std::string& prefix) + { + if (text == "") + return ""; + else + return "\n" + prefix + ": " + text; + } + + std::string ToolTips::getCountString(const int value) + { + if (value == 1) + return ""; + else + return " (" + boost::lexical_cast(value) + ")"; + } + + void ToolTips::toggleFullHelp() + { + mFullHelp = !mFullHelp; + } + + bool ToolTips::getFullHelp() const + { + return mFullHelp; + } + + void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) + { + mFocusToolTipX = (min_x + max_x) / 2; + mFocusToolTipY = min_y; + } + + void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId) + { + if (skillId == -1) + return; + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const ESM::Skill* skill = store.get().find(skillId); + assert(skill); + + const ESM::Attribute* attr = + store.get().find(skill->mData.mAttribute); + assert(attr); + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip"); + widget->setUserString("Caption_SkillNoProgressName", "#{"+skillNameId+"}"); + widget->setUserString("Caption_SkillNoProgressDescription", skill->mDescription); + widget->setUserString("Caption_SkillNoProgressAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + widget->setUserString("ImageTexture_SkillNoProgressImage", icon); + } + + void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId) + { + if (attributeId == -1) + return; + + std::string icon = ESM::Attribute::sAttributeIcons[attributeId]; + std::string name = ESM::Attribute::sGmstAttributeIds[attributeId]; + std::string desc = ESM::Attribute::sGmstAttributeDescIds[attributeId]; + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", "#{"+name+"}"); + widget->setUserString("Caption_AttributeDescription", "#{"+desc+"}"); + widget->setUserString("ImageTexture_AttributeImage", icon); + } + + void ToolTips::createSpecializationToolTip(MyGUI::Widget* widget, const std::string& name, int specId) + { + widget->setUserString("Caption_CenteredCaption", name); + std::string specText; + // get all skills of this specialisation + const MWWorld::Store &skills = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Store::iterator it = skills.begin(); + for (; it != skills.end(); ++it) + { + if (it->mData.mSpecialization == specId) + specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->mIndex] + "}"; + } + widget->setUserString("Caption_CenteredCaptionText", specText); + widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); + widget->setUserString("ToolTipType", "Layout"); + } + + void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::BirthSign *sign = store.get().find(birthsignId); + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "BirthSignToolTip"); + std::string image = sign->mTexture; + image.replace(image.size()-3, 3, "dds"); + widget->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); + std::string text; + + text += sign->mName; + text += "\n#BF9959" + sign->mDescription; + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = sign->mPowers.mList.begin(); + std::vector::const_iterator end = sign->mPowers.mList.end(); + for (; it != end; ++it) + { const std::string &spellId = *it; + const ESM::Spell *spell = store.get().search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->mData.mType); + if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) + continue; // We only want spell, ability and powers. - const ESM::Spell *spell = store.get().find(spellId); - text += "\n#BF9959" + spell->mName; + if (type == ESM::Spell::ST_Ability) + abilities.push_back(spellId); + else if (type == ESM::Spell::ST_Power) + powers.push_back(spellId); + else if (type == ESM::Spell::ST_Spell) + spells.push_back(spellId); } + + struct { + const std::vector &spells; + std::string label; + } + categories[3] = { + {abilities, "sBirthsignmenu1"}, + {powers, "sPowers"}, + {spells, "sBirthsignmenu2"} + }; + + for (int category = 0; category < 3; ++category) + { + for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + { + if (it == categories[category].spells.begin()) + { + text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; + } + + const std::string &spellId = *it; + + const ESM::Spell *spell = store.get().find(spellId); + text += "\n#BF9959" + spell->mName; + } + } + + widget->setUserString("Caption_BirthSignText", text); + } + + void ToolTips::createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace) + { + widget->setUserString("Caption_CenteredCaption", playerRace->mName); + widget->setUserString("Caption_CenteredCaptionText", playerRace->mDescription); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); + } + + void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass) + { + if (playerClass.mName == "") + return; + + int spec = playerClass.mData.mSpecialization; + std::string specStr; + if (spec == 0) + specStr = "#{sSpecializationCombat}"; + else if (spec == 1) + specStr = "#{sSpecializationMagic}"; + else if (spec == 2) + specStr = "#{sSpecializationStealth}"; + + widget->setUserString("Caption_ClassName", playerClass.mName); + widget->setUserString("Caption_ClassDescription", playerClass.mDescription); + widget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "ClassToolTip"); + } + + void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id) + { + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(id); + const std::string &name = ESM::MagicEffect::effectIdToString (id); + + std::string icon = effect->mIcon; + + int slashPos = icon.find("\\"); + icon.insert(slashPos+1, "b_"); + + icon[icon.size()-3] = 'd'; + icon[icon.size()-2] = 'd'; + icon[icon.size()-1] = 's'; + + icon = "icons\\" + icon; + + std::vector schools; + schools.push_back ("#{sSchoolAlteration}"); + schools.push_back ("#{sSchoolConjuration}"); + schools.push_back ("#{sSchoolDestruction}"); + schools.push_back ("#{sSchoolIllusion}"); + schools.push_back ("#{sSchoolMysticism}"); + schools.push_back ("#{sSchoolRestoration}"); + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); + widget->setUserString("Caption_MagicEffectName", "#{" + name + "}"); + widget->setUserString("Caption_MagicEffectDescription", effect->mDescription); + widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]); + widget->setUserString("ImageTexture_MagicEffectImage", icon); + } + + void ToolTips::setDelay(float delay) + { + mDelay = delay; + mRemainingDelay = mDelay; } - widget->setUserString("Caption_BirthSignText", text); -} - -void ToolTips::createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace) -{ - widget->setUserString("Caption_CenteredCaption", playerRace->mName); - widget->setUserString("Caption_CenteredCaptionText", playerRace->mDescription); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); -} - -void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass) -{ - if (playerClass.mName == "") - return; - - int spec = playerClass.mData.mSpecialization; - std::string specStr; - if (spec == 0) - specStr = "#{sSpecializationCombat}"; - else if (spec == 1) - specStr = "#{sSpecializationMagic}"; - else if (spec == 2) - specStr = "#{sSpecializationStealth}"; - - widget->setUserString("Caption_ClassName", playerClass.mName); - widget->setUserString("Caption_ClassDescription", playerClass.mDescription); - widget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "ClassToolTip"); -} - -void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id) -{ - const ESM::MagicEffect* effect = - MWBase::Environment::get().getWorld ()->getStore ().get().find(id); - const std::string &name = ESM::MagicEffect::effectIdToString (id); - - std::string icon = effect->mIcon; - - int slashPos = icon.find("\\"); - icon.insert(slashPos+1, "b_"); - - icon[icon.size()-3] = 'd'; - icon[icon.size()-2] = 'd'; - icon[icon.size()-1] = 's'; - - icon = "icons\\" + icon; - - std::vector schools; - schools.push_back ("#{sSchoolAlteration}"); - schools.push_back ("#{sSchoolConjuration}"); - schools.push_back ("#{sSchoolDestruction}"); - schools.push_back ("#{sSchoolIllusion}"); - schools.push_back ("#{sSchoolMysticism}"); - schools.push_back ("#{sSchoolRestoration}"); - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); - widget->setUserString("Caption_MagicEffectName", "#{" + name + "}"); - widget->setUserString("Caption_MagicEffectDescription", effect->mDescription); - widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]); - widget->setUserString("ImageTexture_MagicEffectImage", icon); -} - -void ToolTips::setDelay(float delay) -{ - mDelay = delay; - mRemainingDelay = mDelay; } diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index e6c8b1d77d..1662c0597d 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -12,882 +12,886 @@ #undef min #undef max -using namespace MWGui; -using namespace MWGui::Widgets; - -/* Helper functions */ - -/* - * Fixes the filename of a texture path to use the correct .dds extension. - * This is needed on some ESM entries which point to a .tga file instead. - */ -void MWGui::Widgets::fixTexturePath(std::string &path) +namespace MWGui { - int offset = path.rfind("."); - if (offset < 0) - return; - path.replace(offset, path.length() - offset, ".dds"); -} - -/* MWSkill */ - -MWSkill::MWSkill() - : mSkillId(ESM::Skill::Length) - , mSkillNameWidget(NULL) - , mSkillValueWidget(NULL) -{ -} - -void MWSkill::setSkillId(ESM::Skill::SkillEnum skill) -{ - mSkillId = skill; - updateWidgets(); -} - -void MWSkill::setSkillNumber(int skill) -{ - if (skill < 0) - setSkillId(ESM::Skill::Length); - else if (skill < ESM::Skill::Length) - setSkillId(static_cast(skill)); - else - throw new std::runtime_error("Skill number out of range"); -} - -void MWSkill::setSkillValue(const SkillValue& value) -{ - mValue = value; - updateWidgets(); -} - -void MWSkill::updateWidgets() -{ - if (mSkillNameWidget) + namespace Widgets { - if (mSkillId == ESM::Skill::Length) + + /* Helper functions */ + + /* + * Fixes the filename of a texture path to use the correct .dds extension. + * This is needed on some ESM entries which point to a .tga file instead. + */ + void fixTexturePath(std::string &path) { - static_cast(mSkillNameWidget)->setCaption(""); - } - else - { - const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); - static_cast(mSkillNameWidget)->setCaption(name); - } - } - if (mSkillValueWidget) - { - SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); - static_cast(mSkillValueWidget)->setCaption(boost::lexical_cast(modified)); - if (modified > base) - mSkillValueWidget->_setWidgetState("increased"); - else if (modified < base) - mSkillValueWidget->_setWidgetState("decreased"); - else - mSkillValueWidget->_setWidgetState("normal"); - } -} - -void MWSkill::onClicked(MyGUI::Widget* _sender) -{ - eventClicked(this); -} - -MWSkill::~MWSkill() -{ -} - -void MWSkill::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mSkillNameWidget, "StatName"); - assignWidget(mSkillValueWidget, "StatValue"); - - MyGUI::Button* button; - assignWidget(button, "StatNameButton"); - if (button) - { - mSkillNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); - } - - button = 0; - assignWidget(button, "StatValueButton"); - if (button) - { - mSkillNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); - } -} - -/* MWAttribute */ - -MWAttribute::MWAttribute() - : mId(-1) - , mAttributeNameWidget(NULL) - , mAttributeValueWidget(NULL) -{ -} - -void MWAttribute::setAttributeId(int attributeId) -{ - mId = attributeId; - updateWidgets(); -} - -void MWAttribute::setAttributeValue(const AttributeValue& value) -{ - mValue = value; - updateWidgets(); -} - -void MWAttribute::onClicked(MyGUI::Widget* _sender) -{ - eventClicked(this); -} - -void MWAttribute::updateWidgets() -{ - if (mAttributeNameWidget) - { - if (mId < 0 || mId >= 8) - { - static_cast(mAttributeNameWidget)->setCaption(""); - } - else - { - static const char *attributes[8] = { - "sAttributeStrength", - "sAttributeIntelligence", - "sAttributeWillpower", - "sAttributeAgility", - "sAttributeSpeed", - "sAttributeEndurance", - "sAttributePersonality", - "sAttributeLuck" - }; - const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); - static_cast(mAttributeNameWidget)->setCaption(name); - } - } - if (mAttributeValueWidget) - { - AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); - static_cast(mAttributeValueWidget)->setCaption(boost::lexical_cast(modified)); - if (modified > base) - mAttributeValueWidget->_setWidgetState("increased"); - else if (modified < base) - mAttributeValueWidget->_setWidgetState("decreased"); - else - mAttributeValueWidget->_setWidgetState("normal"); - } -} - -MWAttribute::~MWAttribute() -{ -} - -void MWAttribute::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mAttributeNameWidget, "StatName"); - assignWidget(mAttributeValueWidget, "StatValue"); - - MyGUI::Button* button; - assignWidget(button, "StatNameButton"); - if (button) - { - mAttributeNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); - } - - button = 0; - assignWidget(button, "StatValueButton"); - if (button) - { - mAttributeValueWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); - } -} - -/* MWSpell */ - -MWSpell::MWSpell() - : mSpellNameWidget(NULL) -{ -} - -void MWSpell::setSpellId(const std::string &spellId) -{ - mId = spellId; - updateWidgets(); -} - -void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags) -{ - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Spell *spell = store.get().search(mId); - MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); - - MWSpellEffectPtr effect = NULL; - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) - { - effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mIsConstant = (flags & MWEffectList::EF_Constant); - params.mNoTarget = (flags & MWEffectList::EF_NoTarget); - effect->setSpellEffect(params); - effects.push_back(effect); - coord.top += effect->getHeight(); - coord.width = std::max(coord.width, effect->getRequestedWidth()); - } -} - -void MWSpell::updateWidgets() -{ - if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) - { - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Spell *spell = store.get().search(mId); - if (spell) - static_cast(mSpellNameWidget)->setCaption(spell->mName); - else - static_cast(mSpellNameWidget)->setCaption(""); - } -} - -void MWSpell::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mSpellNameWidget, "StatName"); -} - -MWSpell::~MWSpell() -{ -} - -/* MWEffectList */ - -MWEffectList::MWEffectList() - : mEffectList(0) -{ -} - -void MWEffectList::setEffectList(const SpellEffectList& list) -{ - mEffectList = list; - updateWidgets(); -} - -void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, bool center, int flags) -{ - // We don't know the width of all the elements beforehand, so we do it in - // 2 steps: first, create all widgets and check their width.... - MWSpellEffectPtr effect = NULL; - int maxwidth = coord.width; - - for (SpellEffectList::iterator it=mEffectList.begin(); - it != mEffectList.end(); ++it) - { - effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; - it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; - effect->setSpellEffect(*it); - effects.push_back(effect); - if (effect->getRequestedWidth() > maxwidth) - maxwidth = effect->getRequestedWidth(); - - coord.top += effect->getHeight(); - } - - // ... then adjust the size for all widgets - for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) - { - effect = static_cast(*it); - bool needcenter = center && (maxwidth > effect->getRequestedWidth()); - int diff = maxwidth - effect->getRequestedWidth(); - if (needcenter) - { - effect->setCoord(diff/2, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); - } - else - { - effect->setCoord(0, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); - } - } - - // inform the parent about width - coord.width = maxwidth; -} - -void MWEffectList::updateWidgets() -{ -} - -void MWEffectList::initialiseOverride() -{ - Base::initialiseOverride(); -} - -MWEffectList::~MWEffectList() -{ -} - -SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) -{ - SpellEffectList result; - std::vector::const_iterator end = effects->mList.end(); - for (std::vector::const_iterator it = effects->mList.begin(); it != end; ++it) - { - SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; - result.push_back(params); - } - return result; -} - -/* MWSpellEffect */ - -MWSpellEffect::MWSpellEffect() - : mImageWidget(NULL) - , mTextWidget(NULL) - , mRequestedWidth(0) -{ -} - -void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) -{ - mEffectParams = params; - updateWidgets(); -} - -void MWSpellEffect::updateWidgets() -{ - if (!mEffectParams.mKnown) - { - mTextWidget->setCaption ("?"); - mRequestedWidth = mTextWidget->getTextSize().width + 24; - mImageWidget->setImageTexture (""); - return; - } - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::MagicEffect *magicEffect = - store.get().search(mEffectParams.mEffectID); - - assert(magicEffect); - - std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); - std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); - std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; - std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); - std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); - - std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); - std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); - - if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); - } - if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); - } - - if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) - { - if (mEffectParams.mMagnMin == mEffectParams.mMagnMax) - spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts); - else - { - spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + to + boost::lexical_cast(mEffectParams.mMagnMax) + " " + pts; - } - } - - // constant effects have no duration and no target - if (!mEffectParams.mIsConstant) - { - if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + int offset = path.rfind("."); + if (offset < 0) + return; + path.replace(offset, path.length() - offset, ".dds"); } - if (mEffectParams.mArea > 0) + /* MWSkill */ + + MWSkill::MWSkill() + : mSkillId(ESM::Skill::Length) + , mSkillNameWidget(NULL) + , mSkillValueWidget(NULL) { - spellLine += " #{sin} " + boost::lexical_cast(mEffectParams.mArea) + " #{sfootarea}"; } - // potions have no target - if (!mEffectParams.mNoTarget) + void MWSkill::setSkillId(ESM::Skill::SkillEnum skill) { - std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); - if (mEffectParams.mRange == ESM::RT_Self) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); - else if (mEffectParams.mRange == ESM::RT_Touch) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); - else if (mEffectParams.mRange == ESM::RT_Target) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); + mSkillId = skill; + updateWidgets(); } - } - static_cast(mTextWidget)->setCaptionWithReplacing(spellLine); - mRequestedWidth = mTextWidget->getTextSize().width + 24; - - std::string path = std::string("icons\\") + magicEffect->mIcon; - fixTexturePath(path); - mImageWidget->setImageTexture(path); -} - -MWSpellEffect::~MWSpellEffect() -{ -} - -void MWSpellEffect::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mTextWidget, "Text"); - assignWidget(mImageWidget, "Image"); -} - -/* MWDynamicStat */ - -MWDynamicStat::MWDynamicStat() -: mValue(0) -, mMax(1) -, mTextWidget(NULL) -, mBarWidget(NULL) -, mBarTextWidget(NULL) -{ -} - -void MWDynamicStat::setValue(int cur, int max) -{ - mValue = cur; - mMax = max; - - if (mBarWidget) - { - mBarWidget->setProgressRange(mMax); - mBarWidget->setProgressPosition(mValue); - } - - - if (mBarTextWidget) - { - if (mValue >= 0 && mMax > 0) + void MWSkill::setSkillNumber(int skill) { - std::stringstream out; - out << mValue << "/" << mMax; - static_cast(mBarTextWidget)->setCaption(out.str().c_str()); + if (skill < 0) + setSkillId(ESM::Skill::Length); + else if (skill < ESM::Skill::Length) + setSkillId(static_cast(skill)); + else + throw new std::runtime_error("Skill number out of range"); } - else - static_cast(mBarTextWidget)->setCaption(""); - } -} -void MWDynamicStat::setTitle(const std::string& text) -{ - if (mTextWidget) - static_cast(mTextWidget)->setCaption(text); -} -MWDynamicStat::~MWDynamicStat() -{ -} - -void MWDynamicStat::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mTextWidget, "Text"); - assignWidget(mBarWidget, "Bar"); - assignWidget(mBarTextWidget, "BarText"); -} - - - - -// --------------------------------------------------------------------------------------------------------------------- - -void AutoSizedWidget::notifySizeChange (MyGUI::Widget* w) -{ - if (w->getParent () != 0) - { - Box* b = dynamic_cast(w->getParent()); - if (b) - b->notifyChildrenSizeChanged (); - else + void MWSkill::setSkillValue(const SkillValue& value) { - if (mExpandDirection == MyGUI::Align::Left) + mValue = value; + updateWidgets(); + } + + void MWSkill::updateWidgets() + { + if (mSkillNameWidget) { - int hdiff = getRequestedSize ().width - w->getSize().width; - w->setPosition(w->getPosition() - MyGUI::IntPoint(hdiff, 0)); + if (mSkillId == ESM::Skill::Length) + { + static_cast(mSkillNameWidget)->setCaption(""); + } + else + { + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); + static_cast(mSkillNameWidget)->setCaption(name); + } + } + if (mSkillValueWidget) + { + SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); + static_cast(mSkillValueWidget)->setCaption(boost::lexical_cast(modified)); + if (modified > base) + mSkillValueWidget->_setWidgetState("increased"); + else if (modified < base) + mSkillValueWidget->_setWidgetState("decreased"); + else + mSkillValueWidget->_setWidgetState("normal"); } - w->setSize(getRequestedSize ()); } - } -} - -MyGUI::IntSize AutoSizedTextBox::getRequestedSize() -{ - return getTextSize(); -} - -void AutoSizedTextBox::setCaption(const MyGUI::UString& _value) -{ - TextBox::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - TextBox::setPropertyOverride (_key, _value); - } -} - -MyGUI::IntSize AutoSizedEditBox::getRequestedSize() -{ - if (getAlign().isHStretch()) - throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")"); - return MyGUI::IntSize(getSize().width, getTextSize().height); -} - -void AutoSizedEditBox::setCaption(const MyGUI::UString& _value) -{ - EditBox::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - EditBox::setPropertyOverride (_key, _value); - } -} - - -MyGUI::IntSize AutoSizedButton::getRequestedSize() -{ - MyGUI::IntSize size = getTextSize() + MyGUI::IntSize(24,0); - size.height = std::max(24, size.height); - return size; -} - -void AutoSizedButton::setCaption(const MyGUI::UString& _value) -{ - Button::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedButton::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - Button::setPropertyOverride (_key, _value); - } -} - -Box::Box() - : mSpacing(4) - , mPadding(0) - , mAutoResize(false) -{ - -} - -void Box::notifyChildrenSizeChanged () -{ - align(); -} - -void Box::_setPropertyImpl(const std::string& _key, const std::string& _value) -{ - if (_key == "Spacing") - mSpacing = MyGUI::utility::parseValue(_value); - else if (_key == "Padding") - mPadding = MyGUI::utility::parseValue(_value); - else if (_key == "AutoResize") - mAutoResize = MyGUI::utility::parseValue(_value); -} - -void HBox::align () -{ - unsigned int count = getChildCount (); - size_t h_stretched_count = 0; - int total_width = 0; - int total_height = 0; - std::vector< std::pair > sizes; - - for (unsigned int i = 0; i < count; ++i) - { - MyGUI::Widget* w = getChildAt(i); - bool hstretch = w->getUserString ("HStretch") == "true"; - h_stretched_count += hstretch; - AutoSizedWidget* aw = dynamic_cast(w); - if (aw) + void MWSkill::onClicked(MyGUI::Widget* _sender) { - sizes.push_back(std::make_pair(aw->getRequestedSize (), hstretch)); - total_width += aw->getRequestedSize ().width; - total_height = std::max(total_height, aw->getRequestedSize ().height); + eventClicked(this); } - else + + MWSkill::~MWSkill() { - sizes.push_back (std::make_pair(w->getSize(), hstretch)); - total_width += w->getSize().width; - if (!(w->getUserString("VStretch") == "true")) - total_height = std::max(total_height, w->getSize().height); } - if (i != count-1) - total_width += mSpacing; - } - - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) - { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); - return; - } - - - int curX = 0; - for (unsigned int i = 0; i < count; ++i) - { - if (i == 0) - curX += mPadding; - - MyGUI::Widget* w = getChildAt(i); - - bool vstretch = w->getUserString ("VStretch") == "true"; - int height = vstretch ? total_height : sizes[i].first.height; - - MyGUI::IntCoord widgetCoord; - widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; - int width = sizes[i].second ? sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count - : sizes[i].first.width; - widgetCoord.width = width; - widgetCoord.height = height; - w->setCoord(widgetCoord); - curX += width; - - if (i != count-1) - curX += mSpacing; - } -} - -void HBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - Box::_setPropertyImpl (_key, _value); -} - -void HBox::setSize (const MyGUI::IntSize& _value) -{ - MyGUI::Widget::setSize (_value); - align(); -} - -void HBox::setCoord (const MyGUI::IntCoord& _value) -{ - MyGUI::Widget::setCoord (_value); - align(); -} - -void HBox::onWidgetCreated(MyGUI::Widget* _widget) -{ - align(); -} - -MyGUI::IntSize HBox::getRequestedSize () -{ - MyGUI::IntSize size(0,0); - for (unsigned int i = 0; i < getChildCount (); ++i) - { - AutoSizedWidget* w = dynamic_cast(getChildAt(i)); - if (w) + void MWSkill::initialiseOverride() { - MyGUI::IntSize requested = w->getRequestedSize (); - size.height = std::max(size.height, requested.height); - size.width = size.width + requested.width; - if (i != getChildCount()-1) - size.width += mSpacing; + Base::initialiseOverride(); + + assignWidget(mSkillNameWidget, "StatName"); + assignWidget(mSkillValueWidget, "StatValue"); + + MyGUI::Button* button; + assignWidget(button, "StatNameButton"); + if (button) + { + mSkillNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); + } + + button = 0; + assignWidget(button, "StatValueButton"); + if (button) + { + mSkillNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); + } } - else + + /* MWAttribute */ + + MWAttribute::MWAttribute() + : mId(-1) + , mAttributeNameWidget(NULL) + , mAttributeValueWidget(NULL) { - MyGUI::IntSize requested = getChildAt(i)->getSize (); - size.height = std::max(size.height, requested.height); - - if (getChildAt(i)->getUserString("HStretch") != "true") - size.width = size.width + requested.width; - - if (i != getChildCount()-1) - size.width += mSpacing; } - size.height += mPadding*2; - size.width += mPadding*2; - } - return size; -} - - - -void VBox::align () -{ - unsigned int count = getChildCount (); - size_t v_stretched_count = 0; - int total_height = 0; - int total_width = 0; - std::vector< std::pair > sizes; - for (unsigned int i = 0; i < count; ++i) - { - MyGUI::Widget* w = getChildAt(i); - bool vstretch = w->getUserString ("VStretch") == "true"; - v_stretched_count += vstretch; - AutoSizedWidget* aw = dynamic_cast(w); - if (aw) + void MWAttribute::setAttributeId(int attributeId) { - sizes.push_back(std::make_pair(aw->getRequestedSize (), vstretch)); - total_height += aw->getRequestedSize ().height; - total_width = std::max(total_width, aw->getRequestedSize ().width); + mId = attributeId; + updateWidgets(); } - else + + void MWAttribute::setAttributeValue(const AttributeValue& value) { - sizes.push_back (std::make_pair(w->getSize(), vstretch)); - total_height += w->getSize().height; - - if (!(w->getUserString("HStretch") == "true")) - total_width = std::max(total_width, w->getSize().width); + mValue = value; + updateWidgets(); } - if (i != count-1) - total_height += mSpacing; - } + void MWAttribute::onClicked(MyGUI::Widget* _sender) + { + eventClicked(this); + } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) - { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); - return; - } + void MWAttribute::updateWidgets() + { + if (mAttributeNameWidget) + { + if (mId < 0 || mId >= 8) + { + static_cast(mAttributeNameWidget)->setCaption(""); + } + else + { + static const char *attributes[8] = { + "sAttributeStrength", + "sAttributeIntelligence", + "sAttributeWillpower", + "sAttributeAgility", + "sAttributeSpeed", + "sAttributeEndurance", + "sAttributePersonality", + "sAttributeLuck" + }; + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); + static_cast(mAttributeNameWidget)->setCaption(name); + } + } + if (mAttributeValueWidget) + { + AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); + static_cast(mAttributeValueWidget)->setCaption(boost::lexical_cast(modified)); + if (modified > base) + mAttributeValueWidget->_setWidgetState("increased"); + else if (modified < base) + mAttributeValueWidget->_setWidgetState("decreased"); + else + mAttributeValueWidget->_setWidgetState("normal"); + } + } + + MWAttribute::~MWAttribute() + { + } + + void MWAttribute::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mAttributeNameWidget, "StatName"); + assignWidget(mAttributeValueWidget, "StatValue"); + + MyGUI::Button* button; + assignWidget(button, "StatNameButton"); + if (button) + { + mAttributeNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); + } + + button = 0; + assignWidget(button, "StatValueButton"); + if (button) + { + mAttributeValueWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); + } + } + + /* MWSpell */ + + MWSpell::MWSpell() + : mSpellNameWidget(NULL) + { + } + + void MWSpell::setSpellId(const std::string &spellId) + { + mId = spellId; + updateWidgets(); + } + + void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell *spell = store.get().search(mId); + MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); + + MWSpellEffectPtr effect = NULL; + std::vector::const_iterator end = spell->mEffects.mList.end(); + for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + { + effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); + SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + params.mIsConstant = (flags & MWEffectList::EF_Constant); + params.mNoTarget = (flags & MWEffectList::EF_NoTarget); + effect->setSpellEffect(params); + effects.push_back(effect); + coord.top += effect->getHeight(); + coord.width = std::max(coord.width, effect->getRequestedWidth()); + } + } + + void MWSpell::updateWidgets() + { + if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell *spell = store.get().search(mId); + if (spell) + static_cast(mSpellNameWidget)->setCaption(spell->mName); + else + static_cast(mSpellNameWidget)->setCaption(""); + } + } + + void MWSpell::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mSpellNameWidget, "StatName"); + } + + MWSpell::~MWSpell() + { + } + + /* MWEffectList */ + + MWEffectList::MWEffectList() + : mEffectList(0) + { + } + + void MWEffectList::setEffectList(const SpellEffectList& list) + { + mEffectList = list; + updateWidgets(); + } + + void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, bool center, int flags) + { + // We don't know the width of all the elements beforehand, so we do it in + // 2 steps: first, create all widgets and check their width.... + MWSpellEffectPtr effect = NULL; + int maxwidth = coord.width; + + for (SpellEffectList::iterator it=mEffectList.begin(); + it != mEffectList.end(); ++it) + { + effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); + it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; + it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; + effect->setSpellEffect(*it); + effects.push_back(effect); + if (effect->getRequestedWidth() > maxwidth) + maxwidth = effect->getRequestedWidth(); + + coord.top += effect->getHeight(); + } + + // ... then adjust the size for all widgets + for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) + { + effect = static_cast(*it); + bool needcenter = center && (maxwidth > effect->getRequestedWidth()); + int diff = maxwidth - effect->getRequestedWidth(); + if (needcenter) + { + effect->setCoord(diff/2, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); + } + else + { + effect->setCoord(0, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); + } + } + + // inform the parent about width + coord.width = maxwidth; + } + + void MWEffectList::updateWidgets() + { + } + + void MWEffectList::initialiseOverride() + { + Base::initialiseOverride(); + } + + MWEffectList::~MWEffectList() + { + } + + SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) + { + SpellEffectList result; + std::vector::const_iterator end = effects->mList.end(); + for (std::vector::const_iterator it = effects->mList.begin(); it != end; ++it) + { + SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + params.mArea = it->mArea; + result.push_back(params); + } + return result; + } + + /* MWSpellEffect */ + + MWSpellEffect::MWSpellEffect() + : mImageWidget(NULL) + , mTextWidget(NULL) + , mRequestedWidth(0) + { + } + + void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) + { + mEffectParams = params; + updateWidgets(); + } + + void MWSpellEffect::updateWidgets() + { + if (!mEffectParams.mKnown) + { + mTextWidget->setCaption ("?"); + mRequestedWidth = mTextWidget->getTextSize().width + 24; + mImageWidget->setImageTexture (""); + return; + } + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::MagicEffect *magicEffect = + store.get().search(mEffectParams.mEffectID); + + assert(magicEffect); + + std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); + std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; + std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); + std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); + + std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); + std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); + + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); + } + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); + } + + if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) + { + if (mEffectParams.mMagnMin == mEffectParams.mMagnMax) + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts); + else + { + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + to + boost::lexical_cast(mEffectParams.mMagnMax) + " " + pts; + } + } + + // constant effects have no duration and no target + if (!mEffectParams.mIsConstant) + { + if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + } + + if (mEffectParams.mArea > 0) + { + spellLine += " #{sin} " + boost::lexical_cast(mEffectParams.mArea) + " #{sfootarea}"; + } + + // potions have no target + if (!mEffectParams.mNoTarget) + { + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); + if (mEffectParams.mRange == ESM::RT_Self) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); + else if (mEffectParams.mRange == ESM::RT_Touch) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); + else if (mEffectParams.mRange == ESM::RT_Target) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); + } + } + + static_cast(mTextWidget)->setCaptionWithReplacing(spellLine); + mRequestedWidth = mTextWidget->getTextSize().width + 24; + + std::string path = std::string("icons\\") + magicEffect->mIcon; + fixTexturePath(path); + mImageWidget->setImageTexture(path); + } + + MWSpellEffect::~MWSpellEffect() + { + } + + void MWSpellEffect::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mTextWidget, "Text"); + assignWidget(mImageWidget, "Image"); + } + + /* MWDynamicStat */ + + MWDynamicStat::MWDynamicStat() + : mValue(0) + , mMax(1) + , mTextWidget(NULL) + , mBarWidget(NULL) + , mBarTextWidget(NULL) + { + } + + void MWDynamicStat::setValue(int cur, int max) + { + mValue = cur; + mMax = max; + + if (mBarWidget) + { + mBarWidget->setProgressRange(mMax); + mBarWidget->setProgressPosition(mValue); + } - int curY = 0; - for (unsigned int i = 0; i < count; ++i) - { - if (i==0) - curY += mPadding; + if (mBarTextWidget) + { + if (mValue >= 0 && mMax > 0) + { + std::stringstream out; + out << mValue << "/" << mMax; + static_cast(mBarTextWidget)->setCaption(out.str().c_str()); + } + else + static_cast(mBarTextWidget)->setCaption(""); + } + } + void MWDynamicStat::setTitle(const std::string& text) + { + if (mTextWidget) + static_cast(mTextWidget)->setCaption(text); + } - MyGUI::Widget* w = getChildAt(i); + MWDynamicStat::~MWDynamicStat() + { + } - bool hstretch = w->getUserString ("HStretch") == "true"; - int width = hstretch ? total_width : sizes[i].first.width; + void MWDynamicStat::initialiseOverride() + { + Base::initialiseOverride(); - MyGUI::IntCoord widgetCoord; - widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; - int height = sizes[i].second ? sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count - : sizes[i].first.height; - widgetCoord.height = height; - widgetCoord.width = width; - w->setCoord(widgetCoord); - curY += height; + assignWidget(mTextWidget, "Text"); + assignWidget(mBarWidget, "Bar"); + assignWidget(mBarTextWidget, "BarText"); + } - if (i != count-1) - curY += mSpacing; + + + + // --------------------------------------------------------------------------------------------------------------------- + + void AutoSizedWidget::notifySizeChange (MyGUI::Widget* w) + { + if (w->getParent () != 0) + { + Box* b = dynamic_cast(w->getParent()); + if (b) + b->notifyChildrenSizeChanged (); + else + { + if (mExpandDirection == MyGUI::Align::Left) + { + int hdiff = getRequestedSize ().width - w->getSize().width; + w->setPosition(w->getPosition() - MyGUI::IntPoint(hdiff, 0)); + } + w->setSize(getRequestedSize ()); + } + } + } + + + MyGUI::IntSize AutoSizedTextBox::getRequestedSize() + { + return getTextSize(); + } + + void AutoSizedTextBox::setCaption(const MyGUI::UString& _value) + { + TextBox::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + TextBox::setPropertyOverride (_key, _value); + } + } + + MyGUI::IntSize AutoSizedEditBox::getRequestedSize() + { + if (getAlign().isHStretch()) + throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")"); + return MyGUI::IntSize(getSize().width, getTextSize().height); + } + + void AutoSizedEditBox::setCaption(const MyGUI::UString& _value) + { + EditBox::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + EditBox::setPropertyOverride (_key, _value); + } + } + + + MyGUI::IntSize AutoSizedButton::getRequestedSize() + { + MyGUI::IntSize size = getTextSize() + MyGUI::IntSize(24,0); + size.height = std::max(24, size.height); + return size; + } + + void AutoSizedButton::setCaption(const MyGUI::UString& _value) + { + Button::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedButton::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + Button::setPropertyOverride (_key, _value); + } + } + + Box::Box() + : mSpacing(4) + , mPadding(0) + , mAutoResize(false) + { + + } + + void Box::notifyChildrenSizeChanged () + { + align(); + } + + void Box::_setPropertyImpl(const std::string& _key, const std::string& _value) + { + if (_key == "Spacing") + mSpacing = MyGUI::utility::parseValue(_value); + else if (_key == "Padding") + mPadding = MyGUI::utility::parseValue(_value); + else if (_key == "AutoResize") + mAutoResize = MyGUI::utility::parseValue(_value); + } + + void HBox::align () + { + unsigned int count = getChildCount (); + size_t h_stretched_count = 0; + int total_width = 0; + int total_height = 0; + std::vector< std::pair > sizes; + + for (unsigned int i = 0; i < count; ++i) + { + MyGUI::Widget* w = getChildAt(i); + bool hstretch = w->getUserString ("HStretch") == "true"; + h_stretched_count += hstretch; + AutoSizedWidget* aw = dynamic_cast(w); + if (aw) + { + sizes.push_back(std::make_pair(aw->getRequestedSize (), hstretch)); + total_width += aw->getRequestedSize ().width; + total_height = std::max(total_height, aw->getRequestedSize ().height); + } + else + { + sizes.push_back (std::make_pair(w->getSize(), hstretch)); + total_width += w->getSize().width; + if (!(w->getUserString("VStretch") == "true")) + total_height = std::max(total_height, w->getSize().height); + } + + if (i != count-1) + total_width += mSpacing; + } + + if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + { + setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + return; + } + + + int curX = 0; + for (unsigned int i = 0; i < count; ++i) + { + if (i == 0) + curX += mPadding; + + MyGUI::Widget* w = getChildAt(i); + + bool vstretch = w->getUserString ("VStretch") == "true"; + int height = vstretch ? total_height : sizes[i].first.height; + + MyGUI::IntCoord widgetCoord; + widgetCoord.left = curX; + widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + int width = sizes[i].second ? sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count + : sizes[i].first.width; + widgetCoord.width = width; + widgetCoord.height = height; + w->setCoord(widgetCoord); + curX += width; + + if (i != count-1) + curX += mSpacing; + } + } + + void HBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + Box::_setPropertyImpl (_key, _value); + } + + void HBox::setSize (const MyGUI::IntSize& _value) + { + MyGUI::Widget::setSize (_value); + align(); + } + + void HBox::setCoord (const MyGUI::IntCoord& _value) + { + MyGUI::Widget::setCoord (_value); + align(); + } + + void HBox::onWidgetCreated(MyGUI::Widget* _widget) + { + align(); + } + + MyGUI::IntSize HBox::getRequestedSize () + { + MyGUI::IntSize size(0,0); + for (unsigned int i = 0; i < getChildCount (); ++i) + { + AutoSizedWidget* w = dynamic_cast(getChildAt(i)); + if (w) + { + MyGUI::IntSize requested = w->getRequestedSize (); + size.height = std::max(size.height, requested.height); + size.width = size.width + requested.width; + if (i != getChildCount()-1) + size.width += mSpacing; + } + else + { + MyGUI::IntSize requested = getChildAt(i)->getSize (); + size.height = std::max(size.height, requested.height); + + if (getChildAt(i)->getUserString("HStretch") != "true") + size.width = size.width + requested.width; + + if (i != getChildCount()-1) + size.width += mSpacing; + } + size.height += mPadding*2; + size.width += mPadding*2; + } + return size; + } + + + + + void VBox::align () + { + unsigned int count = getChildCount (); + size_t v_stretched_count = 0; + int total_height = 0; + int total_width = 0; + std::vector< std::pair > sizes; + for (unsigned int i = 0; i < count; ++i) + { + MyGUI::Widget* w = getChildAt(i); + bool vstretch = w->getUserString ("VStretch") == "true"; + v_stretched_count += vstretch; + AutoSizedWidget* aw = dynamic_cast(w); + if (aw) + { + sizes.push_back(std::make_pair(aw->getRequestedSize (), vstretch)); + total_height += aw->getRequestedSize ().height; + total_width = std::max(total_width, aw->getRequestedSize ().width); + } + else + { + sizes.push_back (std::make_pair(w->getSize(), vstretch)); + total_height += w->getSize().height; + + if (!(w->getUserString("HStretch") == "true")) + total_width = std::max(total_width, w->getSize().width); + } + + if (i != count-1) + total_height += mSpacing; + } + + if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + { + setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + return; + } + + + int curY = 0; + for (unsigned int i = 0; i < count; ++i) + { + if (i==0) + curY += mPadding; + + MyGUI::Widget* w = getChildAt(i); + + bool hstretch = w->getUserString ("HStretch") == "true"; + int width = hstretch ? total_width : sizes[i].first.width; + + MyGUI::IntCoord widgetCoord; + widgetCoord.top = curY; + widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + int height = sizes[i].second ? sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count + : sizes[i].first.height; + widgetCoord.height = height; + widgetCoord.width = width; + w->setCoord(widgetCoord); + curY += height; + + if (i != count-1) + curY += mSpacing; + } + } + + void VBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + Box::_setPropertyImpl (_key, _value); + } + + void VBox::setSize (const MyGUI::IntSize& _value) + { + MyGUI::Widget::setSize (_value); + align(); + } + + void VBox::setCoord (const MyGUI::IntCoord& _value) + { + MyGUI::Widget::setCoord (_value); + align(); + } + + MyGUI::IntSize VBox::getRequestedSize () + { + MyGUI::IntSize size(0,0); + for (unsigned int i = 0; i < getChildCount (); ++i) + { + AutoSizedWidget* w = dynamic_cast(getChildAt(i)); + if (w) + { + MyGUI::IntSize requested = w->getRequestedSize (); + size.width = std::max(size.width, requested.width); + size.height = size.height + requested.height; + if (i != getChildCount()-1) + size.height += mSpacing; + } + else + { + MyGUI::IntSize requested = getChildAt(i)->getSize (); + size.width = std::max(size.width, requested.width); + + if (getChildAt(i)->getUserString("VStretch") != "true") + size.height = size.height + requested.height; + + if (i != getChildCount()-1) + size.height += mSpacing; + } + size.height += mPadding*2; + size.width += mPadding*2; + } + return size; + } + + void VBox::onWidgetCreated(MyGUI::Widget* _widget) + { + align(); + } } } - -void VBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - Box::_setPropertyImpl (_key, _value); -} - -void VBox::setSize (const MyGUI::IntSize& _value) -{ - MyGUI::Widget::setSize (_value); - align(); -} - -void VBox::setCoord (const MyGUI::IntCoord& _value) -{ - MyGUI::Widget::setCoord (_value); - align(); -} - -MyGUI::IntSize VBox::getRequestedSize () -{ - MyGUI::IntSize size(0,0); - for (unsigned int i = 0; i < getChildCount (); ++i) - { - AutoSizedWidget* w = dynamic_cast(getChildAt(i)); - if (w) - { - MyGUI::IntSize requested = w->getRequestedSize (); - size.width = std::max(size.width, requested.width); - size.height = size.height + requested.height; - if (i != getChildCount()-1) - size.height += mSpacing; - } - else - { - MyGUI::IntSize requested = getChildAt(i)->getSize (); - size.width = std::max(size.width, requested.width); - - if (getChildAt(i)->getUserString("VStretch") != "true") - size.height = size.height + requested.height; - - if (i != getChildCount()-1) - size.height += mSpacing; - } - size.height += mPadding*2; - size.width += mPadding*2; - } - return size; -} - -void VBox::onWidgetCreated(MyGUI::Widget* _widget) -{ - align(); -} diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 154234bee5..2171beaffb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -39,1143 +39,1146 @@ #include "companionwindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; - -WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *ogre, - const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage) - : mGuiManager(NULL) - , mRendering(ogre) - , mHud(NULL) - , mMap(NULL) - , mMenu(NULL) - , mStatsWindow(NULL) - , mToolTips(NULL) - , mMessageBoxManager(NULL) - , mConsole(NULL) - , mJournal(NULL) - , mDialogueWindow(NULL) - , mBookWindow(NULL) - , mScrollWindow(NULL) - , mCountDialog(NULL) - , mTradeWindow(NULL) - , mSpellBuyingWindow(NULL) - , mTravelWindow(NULL) - , mSettingsWindow(NULL) - , mConfirmationDialog(NULL) - , mAlchemyWindow(NULL) - , mSpellWindow(NULL) - , mLoadingScreen(NULL) - , mCharGen(NULL) - , mLevelupDialog(NULL) - , mWaitDialog(NULL) - , mSpellCreationDialog(NULL) - , mEnchantingDialog(NULL) - , mTrainingWindow(NULL) - , mMerchantRepair(NULL) - , mRepair(NULL) - , mSoulgemDialog(NULL) - , mCompanionWindow(NULL) - , mPlayerName() - , mPlayerRaceId() - , mPlayerAttributes() - , mPlayerMajorSkills() - , mPlayerMinorSkills() - , mPlayerSkillValues() - , mPlayerHealth() - , mPlayerMagicka() - , mPlayerFatigue() - , mGui(NULL) - , mGarbageDialogs() - , mShown(GW_ALL) - , mAllowed(newGame ? GW_None : GW_ALL) - , mRestAllowed(newGame ? false : true) - , mShowFPSLevel(fpsLevel) - , mFPS(0.0f) - , mTriangleCount(0) - , mBatchCount(0) - , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) - , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) - , mHudEnabled(true) - , mTranslationDataStorage (translationDataStorage) +namespace MWGui { - // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); - mGui = mGuiManager->getGui(); - //Register own widgets with MyGUI - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - - MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); - MyGUI::ResourceManager::getInstance().load("core.xml"); - - MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); - - // Get size info from the Gui object - assert(mGui); - int w = MyGUI::RenderManager::getInstance().getViewSize().width; - int h = MyGUI::RenderManager::getInstance().getViewSize().height; - - MyGUI::Widget* dragAndDropWidget = mGui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); - dragAndDropWidget->setVisible(false); - - mDragAndDrop = new DragAndDrop(); - mDragAndDrop->mIsOnDragAndDrop = false; - mDragAndDrop->mDraggedWidget = 0; - mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - - mMenu = new MainMenu(w,h); - mMap = new MapWindow(cacheDir); - mStatsWindow = new StatsWindow(); - mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(); - mMessageBoxManager = new MessageBoxManager(); - mInventoryWindow = new InventoryWindow(mDragAndDrop); - mTradeWindow = new TradeWindow(); - mSpellBuyingWindow = new SpellBuyingWindow(); - mTravelWindow = new TravelWindow(); - mDialogueWindow = new DialogueWindow(); - mContainerWindow = new ContainerWindow(mDragAndDrop); - mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); - mToolTips = new ToolTips(); - mScrollWindow = new ScrollWindow(); - mBookWindow = new BookWindow(); - mCountDialog = new CountDialog(); - mSettingsWindow = new SettingsWindow(); - mConfirmationDialog = new ConfirmationDialog(); - mAlchemyWindow = new AlchemyWindow(); - mSpellWindow = new SpellWindow(); - mQuickKeysMenu = new QuickKeysMenu(); - mLevelupDialog = new LevelupDialog(); - mWaitDialog = new WaitDialog(); - mSpellCreationDialog = new SpellCreationDialog(); - mEnchantingDialog = new EnchantingDialog(); - mTrainingWindow = new TrainingWindow(); - mMerchantRepair = new MerchantRepair(); - mRepair = new Repair(); - mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); - mLoadingScreen->onResChange (w,h); - - mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); - - mCursor = new Cursor(); - - mHud->setVisible(mHudEnabled); - - mCharGen = new CharacterCreation(); - - // Setup player stats - for (int i = 0; i < ESM::Attribute::Length; ++i) + WindowManager::WindowManager( + const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *ogre, + const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + Translation::Storage& translationDataStorage) + : mGuiManager(NULL) + , mRendering(ogre) + , mHud(NULL) + , mMap(NULL) + , mMenu(NULL) + , mStatsWindow(NULL) + , mToolTips(NULL) + , mMessageBoxManager(NULL) + , mConsole(NULL) + , mJournal(NULL) + , mDialogueWindow(NULL) + , mBookWindow(NULL) + , mScrollWindow(NULL) + , mCountDialog(NULL) + , mTradeWindow(NULL) + , mSpellBuyingWindow(NULL) + , mTravelWindow(NULL) + , mSettingsWindow(NULL) + , mConfirmationDialog(NULL) + , mAlchemyWindow(NULL) + , mSpellWindow(NULL) + , mLoadingScreen(NULL) + , mCharGen(NULL) + , mLevelupDialog(NULL) + , mWaitDialog(NULL) + , mSpellCreationDialog(NULL) + , mEnchantingDialog(NULL) + , mTrainingWindow(NULL) + , mMerchantRepair(NULL) + , mRepair(NULL) + , mSoulgemDialog(NULL) + , mCompanionWindow(NULL) + , mPlayerName() + , mPlayerRaceId() + , mPlayerAttributes() + , mPlayerMajorSkills() + , mPlayerMinorSkills() + , mPlayerSkillValues() + , mPlayerHealth() + , mPlayerMagicka() + , mPlayerFatigue() + , mGui(NULL) + , mGarbageDialogs() + , mShown(GW_ALL) + , mAllowed(newGame ? GW_None : GW_ALL) + , mRestAllowed(newGame ? false : true) + , mShowFPSLevel(fpsLevel) + , mFPS(0.0f) + , mTriangleCount(0) + , mBatchCount(0) + , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) + , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) + , mHudEnabled(true) + , mTranslationDataStorage (translationDataStorage) { - mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat())); - } + // Set up the GUI system + mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); + mGui = mGuiManager->getGui(); - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat())); - } + //Register own widgets with MyGUI + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - unsetSelectedSpell(); - unsetSelectedWeapon(); + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + MyGUI::ResourceManager::getInstance().load("core.xml"); - if (newGame) - disallowAll (); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); - // Set up visibility - updateVisible(); -} + // Get size info from the Gui object + assert(mGui); + int w = MyGUI::RenderManager::getInstance().getViewSize().width; + int h = MyGUI::RenderManager::getInstance().getViewSize().height; -WindowManager::~WindowManager() -{ - delete mConsole; - delete mMessageBoxManager; - delete mHud; - delete mMap; - delete mMenu; - delete mStatsWindow; - delete mJournal; - delete mDialogueWindow; - delete mContainerWindow; - delete mInventoryWindow; - delete mToolTips; - delete mCharGen; - delete mDragAndDrop; - delete mBookWindow; - delete mScrollWindow; - delete mTradeWindow; - delete mSpellBuyingWindow; - delete mTravelWindow; - delete mSettingsWindow; - delete mConfirmationDialog; - delete mAlchemyWindow; - delete mSpellWindow; - delete mLoadingScreen; - delete mLevelupDialog; - delete mWaitDialog; - delete mSpellCreationDialog; - delete mEnchantingDialog; - delete mTrainingWindow; - delete mCountDialog; - delete mQuickKeysMenu; - delete mMerchantRepair; - delete mRepair; - delete mSoulgemDialog; - delete mCursor; + MyGUI::Widget* dragAndDropWidget = mGui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); + dragAndDropWidget->setVisible(false); - cleanupGarbage(); + mDragAndDrop = new DragAndDrop(); + mDragAndDrop->mIsOnDragAndDrop = false; + mDragAndDrop->mDraggedWidget = 0; + mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - delete mGuiManager; -} + mMenu = new MainMenu(w,h); + mMap = new MapWindow(cacheDir); + mStatsWindow = new StatsWindow(); + mConsole = new Console(w,h, consoleOnlyScripts); + mJournal = new JournalWindow(); + mMessageBoxManager = new MessageBoxManager(); + mInventoryWindow = new InventoryWindow(mDragAndDrop); + mTradeWindow = new TradeWindow(); + mSpellBuyingWindow = new SpellBuyingWindow(); + mTravelWindow = new TravelWindow(); + mDialogueWindow = new DialogueWindow(); + mContainerWindow = new ContainerWindow(mDragAndDrop); + mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mBookWindow = new BookWindow(); + mCountDialog = new CountDialog(); + mSettingsWindow = new SettingsWindow(); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); + mSpellWindow = new SpellWindow(); + mQuickKeysMenu = new QuickKeysMenu(); + mLevelupDialog = new LevelupDialog(); + mWaitDialog = new WaitDialog(); + mSpellCreationDialog = new SpellCreationDialog(); + mEnchantingDialog = new EnchantingDialog(); + mTrainingWindow = new TrainingWindow(); + mMerchantRepair = new MerchantRepair(); + mRepair = new Repair(); + mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); -void WindowManager::cleanupGarbage() -{ - // Delete any dialogs which are no longer in use - if (!mGarbageDialogs.empty()) - { - for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); + mLoadingScreen->onResChange (w,h); + + mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + + mCursor = new Cursor(); + + mHud->setVisible(mHudEnabled); + + mCharGen = new CharacterCreation(); + + // Setup player stats + for (int i = 0; i < ESM::Attribute::Length; ++i) { - delete *it; + mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat())); } - mGarbageDialogs.clear(); - } -} -void WindowManager::update() -{ - cleanupGarbage(); - - mHud->setFPS(mFPS); - mHud->setTriangleCount(mTriangleCount); - mHud->setBatchCount(mBatchCount); - - mHud->update(); - - mCursor->update(); -} - -void WindowManager::updateVisible() -{ - // Start out by hiding everything except the HUD - mMap->setVisible(false); - mMenu->setVisible(false); - mStatsWindow->setVisible(false); - mConsole->disable(); - mJournal->setVisible(false); - mDialogueWindow->setVisible(false); - mContainerWindow->setVisible(false); - mInventoryWindow->setVisible(false); - mScrollWindow->setVisible(false); - mBookWindow->setVisible(false); - mTradeWindow->setVisible(false); - mSpellBuyingWindow->setVisible(false); - mTravelWindow->setVisible(false); - mSettingsWindow->setVisible(false); - mAlchemyWindow->setVisible(false); - mSpellWindow->setVisible(false); - mQuickKeysMenu->setVisible(false); - mLevelupDialog->setVisible(false); - mWaitDialog->setVisible(false); - mSpellCreationDialog->setVisible(false); - mEnchantingDialog->setVisible(false); - mTrainingWindow->setVisible(false); - mMerchantRepair->setVisible(false); - mRepair->setVisible(false); - mCompanionWindow->setVisible(false); - - mHud->setVisible(mHudEnabled); - - bool gameMode = !isGuiMode(); - - mInputBlocker->setVisible (gameMode); - - if (gameMode) - mToolTips->enterGameMode(); - else - mToolTips->enterGuiMode(); - - if (gameMode) - MyGUI::InputManager::getInstance ().setKeyFocusWidget (NULL); - - setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); - setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); - setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); - setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); - - // If in game mode, show only the pinned windows - if (gameMode) - { - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - - return; - } - - GuiMode mode = mGuiModes.back(); - - switch(mode) { - case GM_QuickKeysMenu: - mQuickKeysMenu->setVisible (true); - break; - case GM_MainMenu: - mMenu->setVisible(true); - break; - case GM_Settings: - mSettingsWindow->setVisible(true); - break; - case GM_Console: - // Show the pinned windows - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - - mConsole->enable(); - break; - case GM_Scroll: - mScrollWindow->setVisible(true); - break; - case GM_Book: - mBookWindow->setVisible(true); - break; - case GM_Alchemy: - mAlchemyWindow->setVisible(true); - break; - case GM_Rest: - mWaitDialog->setVisible(true); - break; - case GM_RestBed: - mWaitDialog->setVisible(true); - mWaitDialog->bedActivated(); - break; - case GM_Levelup: - mLevelupDialog->setVisible(true); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - mCharGen->spawnDialog(mode); - break; - case GM_Inventory: + for (int i = 0; i < ESM::Skill::Length; ++i) { - // First, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed; - - // Show the windows we want - mMap ->setVisible(eff & GW_Map); - mStatsWindow ->setVisible(eff & GW_Stats); - mInventoryWindow->setVisible(eff & GW_Inventory); - mSpellWindow ->setVisible(eff & GW_Magic); - break; + mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat())); } - case GM_Container: - mContainerWindow->setVisible(true); - mInventoryWindow->setVisible(true); - break; - case GM_Companion: - mCompanionWindow->setVisible(true); - mInventoryWindow->setVisible(true); - break; - case GM_Dialogue: - mDialogueWindow->setVisible(true); - break; - case GM_Barter: - mInventoryWindow->setVisible(true); - mTradeWindow->setVisible(true); - break; - case GM_SpellBuying: - mSpellBuyingWindow->setVisible(true); - break; - case GM_Travel: - mTravelWindow->setVisible(true); - break; - case GM_SpellCreation: - mSpellCreationDialog->setVisible(true); - break; - case GM_Enchanting: - mEnchantingDialog->setVisible(true); - break; - case GM_Training: - mTrainingWindow->setVisible(true); - break; - case GM_MerchantRepair: - mMerchantRepair->setVisible(true); - break; - case GM_Repair: - mRepair->setVisible(true); - break; - case GM_Journal: - mJournal->setVisible(true); - break; - case GM_LoadingWallpaper: - mHud->setVisible(false); - mCursor->setVisible(false); - break; - case GM_Loading: - // Show the pinned windows - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - mCursor->setVisible(false); - break; - case GM_Video: - mCursor->setVisible(false); - mHud->setVisible(false); - break; - default: - // Unsupported mode, switch back to game - break; - } -} + unsetSelectedSpell(); + unsetSelectedWeapon(); -void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - mStatsWindow->setValue (id, value); - mCharGen->setValue(id, value); + if (newGame) + disallowAll (); - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8" - }; - static ESM::Attribute::AttributeID attributes[] = - { - ESM::Attribute::Strength, - ESM::Attribute::Intelligence, - ESM::Attribute::Willpower, - ESM::Attribute::Agility, - ESM::Attribute::Speed, - ESM::Attribute::Endurance, - ESM::Attribute::Personality, - ESM::Attribute::Luck - }; - for (size_t i = 0; i < sizeof(ids)/sizeof(ids[0]); ++i) - { - if (id != ids[i]) - continue; - mPlayerAttributes[attributes[i]] = value; - break; - } -} - - -void WindowManager::setValue (int parSkill, const MWMechanics::Stat& value) -{ - /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we - /// allow custom skills. - mStatsWindow->setValue(static_cast (parSkill), value); - mCharGen->setValue(static_cast (parSkill), value); - mPlayerSkillValues[parSkill] = value; -} - -void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - mStatsWindow->setValue (id, value); - mHud->setValue (id, value); - mCharGen->setValue(id, value); - if (id == "HBar") - { - mPlayerHealth = value; - mCharGen->setPlayerHealth (value); - } - else if (id == "MBar") - { - mPlayerMagicka = value; - mCharGen->setPlayerMagicka (value); - } - else if (id == "FBar") - { - mPlayerFatigue = value; - mCharGen->setPlayerFatigue (value); - } -} - -#if 0 -MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) -{ - if(id == "HBar") - return layerHealth; - else if (id == "MBar") - return mPlayerMagicka; - else if (id == "FBar") - return mPlayerFatigue; -} -#endif - -void WindowManager::setValue (const std::string& id, const std::string& value) -{ - mStatsWindow->setValue (id, value); - if (id=="name") - mPlayerName = value; - else if (id=="race") - mPlayerRaceId = value; -} - -void WindowManager::setValue (const std::string& id, int value) -{ - mStatsWindow->setValue (id, value); -} - -void WindowManager::setPlayerClass (const ESM::Class &class_) -{ - mStatsWindow->setValue("class", class_.mName); -} - -void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) -{ - mStatsWindow->configureSkills (major, minor); - mCharGen->configureSkills(major, minor); - mPlayerMajorSkills = major; - mPlayerMinorSkills = minor; -} - -void WindowManager::setReputation (int reputation) -{ - mStatsWindow->setReputation (reputation); -} - -void WindowManager::setBounty (int bounty) -{ - mStatsWindow->setBounty (bounty); -} - -void WindowManager::updateSkillArea() -{ - mStatsWindow->updateSkillArea(); -} - -void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) -{ - if (!dialog) - return; - dialog->setVisible(false); - mGarbageDialogs.push_back(dialog); -} - -void WindowManager::messageBox (const std::string& message, const std::vector& buttons) -{ - if(buttons.empty()){ - /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ - if(!mGuiModes.empty() && mGuiModes.back() == GM_Dialogue) - mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); - else - mMessageBoxManager->createMessageBox(message); + // Set up visibility + updateVisible(); } - else + WindowManager::~WindowManager() { - mMessageBoxManager->createInteractiveMessageBox(message, buttons); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); + delete mConsole; + delete mMessageBoxManager; + delete mHud; + delete mMap; + delete mMenu; + delete mStatsWindow; + delete mJournal; + delete mDialogueWindow; + delete mContainerWindow; + delete mInventoryWindow; + delete mToolTips; + delete mCharGen; + delete mDragAndDrop; + delete mBookWindow; + delete mScrollWindow; + delete mTradeWindow; + delete mSpellBuyingWindow; + delete mTravelWindow; + delete mSettingsWindow; + delete mConfirmationDialog; + delete mAlchemyWindow; + delete mSpellWindow; + delete mLoadingScreen; + delete mLevelupDialog; + delete mWaitDialog; + delete mSpellCreationDialog; + delete mEnchantingDialog; + delete mTrainingWindow; + delete mCountDialog; + delete mQuickKeysMenu; + delete mMerchantRepair; + delete mRepair; + delete mSoulgemDialog; + delete mCursor; + + cleanupGarbage(); + + delete mGuiManager; } -} -void WindowManager::enterPressed () -{ - mMessageBoxManager->enterPressed(); -} - -int WindowManager::readPressedButton () -{ - return mMessageBoxManager->readPressedButton(); -} - -std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) -{ - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().search(id); - - if (setting && setting->mValue.getType()==ESM::VT_String) - return setting->mValue.getString(); - - return default_; -} - -void WindowManager::onDialogueWindowBye() -{ - if (mDialogueWindow) + void WindowManager::cleanupGarbage() { - //FIXME set some state and stuff? - //removeDialog(dialogueWindow); + // Delete any dialogs which are no longer in use + if (!mGarbageDialogs.empty()) + { + for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + { + delete *it; + } + mGarbageDialogs.clear(); + } + } + + void WindowManager::update() + { + cleanupGarbage(); + + mHud->setFPS(mFPS); + mHud->setTriangleCount(mTriangleCount); + mHud->setBatchCount(mBatchCount); + + mHud->update(); + + mCursor->update(); + } + + void WindowManager::updateVisible() + { + // Start out by hiding everything except the HUD + mMap->setVisible(false); + mMenu->setVisible(false); + mStatsWindow->setVisible(false); + mConsole->disable(); + mJournal->setVisible(false); mDialogueWindow->setVisible(false); - } - removeGuiMode(GM_Dialogue); -} + mContainerWindow->setVisible(false); + mInventoryWindow->setVisible(false); + mScrollWindow->setVisible(false); + mBookWindow->setVisible(false); + mTradeWindow->setVisible(false); + mSpellBuyingWindow->setVisible(false); + mTravelWindow->setVisible(false); + mSettingsWindow->setVisible(false); + mAlchemyWindow->setVisible(false); + mSpellWindow->setVisible(false); + mQuickKeysMenu->setVisible(false); + mLevelupDialog->setVisible(false); + mWaitDialog->setVisible(false); + mSpellCreationDialog->setVisible(false); + mEnchantingDialog->setVisible(false); + mTrainingWindow->setVisible(false); + mMerchantRepair->setVisible(false); + mRepair->setVisible(false); + mCompanionWindow->setVisible(false); -void WindowManager::onFrame (float frameDuration) -{ - mMessageBoxManager->onFrame(frameDuration); + mHud->setVisible(mHudEnabled); - mToolTips->onFrame(frameDuration); + bool gameMode = !isGuiMode(); - if (mDragAndDrop->mIsOnDragAndDrop) - { - assert(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - } + mInputBlocker->setVisible (gameMode); - mDialogueWindow->onFrame(); + if (gameMode) + mToolTips->enterGameMode(); + else + mToolTips->enterGuiMode(); - mInventoryWindow->onFrame(); + if (gameMode) + MyGUI::InputManager::getInstance ().setKeyFocusWidget (NULL); - mStatsWindow->onFrame(); + setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); + setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); + setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); + setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); - mWaitDialog->onFrame(frameDuration); - - mHud->onFrame(frameDuration); - - mTrainingWindow->onFrame (frameDuration); - mTradeWindow->onFrame(frameDuration); - - mTrainingWindow->checkReferenceAvailable(); - mDialogueWindow->checkReferenceAvailable(); - mTradeWindow->checkReferenceAvailable(); - mSpellBuyingWindow->checkReferenceAvailable(); - mSpellCreationDialog->checkReferenceAvailable(); - mEnchantingDialog->checkReferenceAvailable(); - mContainerWindow->checkReferenceAvailable(); - mCompanionWindow->checkReferenceAvailable(); - mConsole->checkReferenceAvailable(); -} - -void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) -{ - if (cell->mCell->isExterior()) - { - std::string name; - if (cell->mCell->mName != "") + // If in game mode, show only the pinned windows + if (gameMode) { - name = cell->mCell->mName; - mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + return; } + + GuiMode mode = mGuiModes.back(); + + switch(mode) { + case GM_QuickKeysMenu: + mQuickKeysMenu->setVisible (true); + break; + case GM_MainMenu: + mMenu->setVisible(true); + break; + case GM_Settings: + mSettingsWindow->setVisible(true); + break; + case GM_Console: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + mConsole->enable(); + break; + case GM_Scroll: + mScrollWindow->setVisible(true); + break; + case GM_Book: + mBookWindow->setVisible(true); + break; + case GM_Alchemy: + mAlchemyWindow->setVisible(true); + break; + case GM_Rest: + mWaitDialog->setVisible(true); + break; + case GM_RestBed: + mWaitDialog->setVisible(true); + mWaitDialog->bedActivated(); + break; + case GM_Levelup: + mLevelupDialog->setVisible(true); + break; + case GM_Name: + case GM_Race: + case GM_Class: + case GM_ClassPick: + case GM_ClassCreate: + case GM_Birth: + case GM_ClassGenerate: + case GM_Review: + mCharGen->spawnDialog(mode); + break; + case GM_Inventory: + { + // First, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed; + + // Show the windows we want + mMap ->setVisible(eff & GW_Map); + mStatsWindow ->setVisible(eff & GW_Stats); + mInventoryWindow->setVisible(eff & GW_Inventory); + mSpellWindow ->setVisible(eff & GW_Magic); + break; + } + case GM_Container: + mContainerWindow->setVisible(true); + mInventoryWindow->setVisible(true); + break; + case GM_Companion: + mCompanionWindow->setVisible(true); + mInventoryWindow->setVisible(true); + break; + case GM_Dialogue: + mDialogueWindow->setVisible(true); + break; + case GM_Barter: + mInventoryWindow->setVisible(true); + mTradeWindow->setVisible(true); + break; + case GM_SpellBuying: + mSpellBuyingWindow->setVisible(true); + break; + case GM_Travel: + mTravelWindow->setVisible(true); + break; + case GM_SpellCreation: + mSpellCreationDialog->setVisible(true); + break; + case GM_Enchanting: + mEnchantingDialog->setVisible(true); + break; + case GM_Training: + mTrainingWindow->setVisible(true); + break; + case GM_MerchantRepair: + mMerchantRepair->setVisible(true); + break; + case GM_Repair: + mRepair->setVisible(true); + break; + case GM_Journal: + mJournal->setVisible(true); + break; + case GM_LoadingWallpaper: + mHud->setVisible(false); + mCursor->setVisible(false); + break; + case GM_Loading: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + mCursor->setVisible(false); + break; + case GM_Video: + mCursor->setVisible(false); + mHud->setVisible(false); + break; + default: + // Unsupported mode, switch back to game + break; + } + } + + void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) + { + mStatsWindow->setValue (id, value); + mCharGen->setValue(id, value); + + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8" + }; + static ESM::Attribute::AttributeID attributes[] = + { + ESM::Attribute::Strength, + ESM::Attribute::Intelligence, + ESM::Attribute::Willpower, + ESM::Attribute::Agility, + ESM::Attribute::Speed, + ESM::Attribute::Endurance, + ESM::Attribute::Personality, + ESM::Attribute::Luck + }; + for (size_t i = 0; i < sizeof(ids)/sizeof(ids[0]); ++i) + { + if (id != ids[i]) + continue; + mPlayerAttributes[attributes[i]] = value; + break; + } + } + + + void WindowManager::setValue (int parSkill, const MWMechanics::Stat& value) + { + /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we + /// allow custom skills. + mStatsWindow->setValue(static_cast (parSkill), value); + mCharGen->setValue(static_cast (parSkill), value); + mPlayerSkillValues[parSkill] = value; + } + + void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) + { + mStatsWindow->setValue (id, value); + mHud->setValue (id, value); + mCharGen->setValue(id, value); + if (id == "HBar") + { + mPlayerHealth = value; + mCharGen->setPlayerHealth (value); + } + else if (id == "MBar") + { + mPlayerMagicka = value; + mCharGen->setPlayerMagicka (value); + } + else if (id == "FBar") + { + mPlayerFatigue = value; + mCharGen->setPlayerFatigue (value); + } + } + + #if 0 + MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) + { + if(id == "HBar") + return layerHealth; + else if (id == "MBar") + return mPlayerMagicka; + else if (id == "FBar") + return mPlayerFatigue; + } + #endif + + void WindowManager::setValue (const std::string& id, const std::string& value) + { + mStatsWindow->setValue (id, value); + if (id=="name") + mPlayerName = value; + else if (id=="race") + mPlayerRaceId = value; + } + + void WindowManager::setValue (const std::string& id, int value) + { + mStatsWindow->setValue (id, value); + } + + void WindowManager::setPlayerClass (const ESM::Class &class_) + { + mStatsWindow->setValue("class", class_.mName); + } + + void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) + { + mStatsWindow->configureSkills (major, minor); + mCharGen->configureSkills(major, minor); + mPlayerMajorSkills = major; + mPlayerMinorSkills = minor; + } + + void WindowManager::setReputation (int reputation) + { + mStatsWindow->setReputation (reputation); + } + + void WindowManager::setBounty (int bounty) + { + mStatsWindow->setBounty (bounty); + } + + void WindowManager::updateSkillArea() + { + mStatsWindow->updateSkillArea(); + } + + void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) + { + if (!dialog) + return; + dialog->setVisible(false); + mGarbageDialogs.push_back(dialog); + } + + void WindowManager::messageBox (const std::string& message, const std::vector& buttons) + { + if(buttons.empty()){ + /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ + if(!mGuiModes.empty() && mGuiModes.back() == GM_Dialogue) + mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); + else + mMessageBoxManager->createMessageBox(message); + } + else { - const ESM::Region* region = - MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); - if (region) - name = region->mName; - else - name = getGameSettingString("sDefaultCellname", "Wilderness"); + mMessageBoxManager->createInteractiveMessageBox(message, buttons); + MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); } - - mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY()); - - mMap->setCellName( name ); - mHud->setCellName( name ); - - mMap->setCellPrefix("Cell"); - mHud->setCellPrefix("Cell"); - mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); - mHud->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); } - else + + void WindowManager::enterPressed () { - mMap->setCellName( cell->mCell->mName ); - mHud->setCellName( cell->mCell->mName ); - mMap->setCellPrefix( cell->mCell->mName ); - mHud->setCellPrefix( cell->mCell->mName ); + mMessageBoxManager->enterPressed(); } -} - -void WindowManager::setInteriorMapTexture(const int x, const int y) -{ - mMap->setActiveCell(x,y, true); - mHud->setActiveCell(x,y, true); -} - -void WindowManager::setPlayerPos(const float x, const float y) -{ - mMap->setPlayerPos(x,y); - mHud->setPlayerPos(x,y); -} - -void WindowManager::setPlayerDir(const float x, const float y) -{ - mMap->setPlayerDir(x,y); - mHud->setPlayerDir(x,y); -} - -void WindowManager::setHMSVisibility(bool visible) -{ - mHud->setHmsVisible (visible); -} - -void WindowManager::setMinimapVisibility(bool visible) -{ - mHud->setMinimapVisible (visible); -} - -void WindowManager::toggleFogOfWar() -{ - mMap->toggleFogOfWar(); - mHud->toggleFogOfWar(); -} - -void WindowManager::setFocusObject(const MWWorld::Ptr& focus) -{ - mToolTips->setFocusObject(focus); -} - -void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) -{ - mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y); -} - -void WindowManager::toggleFullHelp() -{ - mToolTips->toggleFullHelp(); -} - -bool WindowManager::getFullHelp() const -{ - return mToolTips->getFullHelp(); -} - -void WindowManager::setWeaponVisibility(bool visible) -{ - mHud->setWeapVisible (visible); -} - -void WindowManager::setSpellVisibility(bool visible) -{ - mHud->setSpellVisible (visible); - mHud->setEffectVisible (visible); -} - -void WindowManager::setMouseVisible(bool visible) -{ - mCursor->setVisible(visible); -} - -void WindowManager::setDragDrop(bool dragDrop) -{ - mToolTips->setEnabled(!dragDrop); - MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); -} - -void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) -{ - std::string tag(_tag); - - std::string tokenToFind = "sCell="; - size_t tokenLength = tokenToFind.length(); - - if (tag.substr(0, tokenLength) == tokenToFind) + int WindowManager::readPressedButton () { - _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); + return mMessageBoxManager->readPressedButton(); } - else + + std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) { const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().find(tag); + MWBase::Environment::get().getWorld()->getStore().get().search(id); if (setting && setting->mValue.getType()==ESM::VT_String) - _result = setting->mValue.getString(); - else - _result = tag; + return setting->mValue.getString(); + + return default_; } -} -void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) -{ - mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); - mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); - - bool changeRes = false; - bool windowRecreated = false; - for (Settings::CategorySettingVector::const_iterator it = changed.begin(); - it != changed.end(); ++it) + void WindowManager::onDialogueWindowBye() { - if (it->first == "Video" && ( - it->second == "resolution x" - || it->second == "resolution y")) + if (mDialogueWindow) { - changeRes = true; + //FIXME set some state and stuff? + //removeDialog(dialogueWindow); + mDialogueWindow->setVisible(false); } - else if (it->first == "Video" && it->second == "vsync") - windowRecreated = true; - else if (it->first == "HUD" && it->second == "crosshair") - mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); - else if (it->first == "GUI" && it->second == "subtitles") - mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); + removeGuiMode(GM_Dialogue); } - if (changeRes) + void WindowManager::onFrame (float frameDuration) { - int x = Settings::Manager::getInt("resolution x", "Video"); - int y = Settings::Manager::getInt("resolution y", "Video"); - mHud->onResChange(x, y); - mConsole->onResChange(x, y); - mMenu->onResChange(x, y); - mSettingsWindow->center(); - mAlchemyWindow->center(); - mScrollWindow->center(); - mBookWindow->center(); - mQuickKeysMenu->center(); - mSpellBuyingWindow->center(); - mLoadingScreen->onResChange (x,y); - mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); - mInputBlocker->setSize(MyGUI::IntSize(x,y)); - } - if (windowRecreated) - { - mGuiManager->updateWindow (mRendering->getWindow ()); - mLoadingScreen->updateWindow (mRendering->getWindow ()); - } -} + mMessageBoxManager->onFrame(frameDuration); -void WindowManager::pushGuiMode(GuiMode mode) -{ - if (mode==GM_Inventory && mAllowed==GW_None) - return; + mToolTips->onFrame(frameDuration); + if (mDragAndDrop->mIsOnDragAndDrop) + { + assert(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + } - // If this mode already exists somewhere in the stack, just bring it to the front. - if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) - { - mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + mDialogueWindow->onFrame(); + + mInventoryWindow->onFrame(); + + mStatsWindow->onFrame(); + + mWaitDialog->onFrame(frameDuration); + + mHud->onFrame(frameDuration); + + mTrainingWindow->onFrame (frameDuration); + mTradeWindow->onFrame(frameDuration); + + mTrainingWindow->checkReferenceAvailable(); + mDialogueWindow->checkReferenceAvailable(); + mTradeWindow->checkReferenceAvailable(); + mSpellBuyingWindow->checkReferenceAvailable(); + mSpellCreationDialog->checkReferenceAvailable(); + mEnchantingDialog->checkReferenceAvailable(); + mContainerWindow->checkReferenceAvailable(); + mCompanionWindow->checkReferenceAvailable(); + mConsole->checkReferenceAvailable(); } - mGuiModes.push_back(mode); - - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::popGuiMode() -{ - if (!mGuiModes.empty()) - mGuiModes.pop_back(); - - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::removeGuiMode(GuiMode mode) -{ - std::vector::iterator it = mGuiModes.begin(); - while (it != mGuiModes.end()) + void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) { - if (*it == mode) - it = mGuiModes.erase(it); + if (cell->mCell->isExterior()) + { + std::string name; + if (cell->mCell->mName != "") + { + name = cell->mCell->mName; + mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); + } + else + { + const ESM::Region* region = + MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); + if (region) + name = region->mName; + else + name = getGameSettingString("sDefaultCellname", "Wilderness"); + } + + mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY()); + + mMap->setCellName( name ); + mHud->setCellName( name ); + + mMap->setCellPrefix("Cell"); + mHud->setCellPrefix("Cell"); + mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); + mHud->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); + } else - ++it; + { + mMap->setCellName( cell->mCell->mName ); + mHud->setCellName( cell->mCell->mName ); + mMap->setCellPrefix( cell->mCell->mName ); + mHud->setCellPrefix( cell->mCell->mName ); + } + } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) -{ - mHud->setSelectedSpell(spellId, successChancePercent); - - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - mSpellWindow->setTitle(spell->mName); -} - -void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) -{ - const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() - .find(MWWorld::Class::get(item).getEnchantment(item)); - - int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; - mHud->setSelectedEnchantItem(item, chargePercent); - mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); -} - -void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) -{ - int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; - mHud->setSelectedWeapon(item, durabilityPercent); - mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); -} - -void WindowManager::unsetSelectedSpell() -{ - mHud->unsetSelectedSpell(); - mSpellWindow->setTitle("#{sNone}"); -} - -void WindowManager::unsetSelectedWeapon() -{ - mHud->unsetSelectedWeapon(); - mInventoryWindow->setTitle("#{sSkillHandtohand}"); -} - -void WindowManager::getMousePosition(int &x, int &y) -{ - const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); - x = pos.left; - y = pos.top; -} - -void WindowManager::getMousePosition(float &x, float &y) -{ - const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); - x = pos.left; - y = pos.top; - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - x /= viewSize.width; - y /= viewSize.height; -} - -bool WindowManager::getWorldMouseOver() -{ - return mHud->getWorldMouseOver(); -} - -void WindowManager::executeInConsole (const std::string& path) -{ - mConsole->executeFile (path); -} - -void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) -{ - mFPS = fps; - mTriangleCount = triangleCount; - mBatchCount = batchCount; -} - -MyGUI::Gui* WindowManager::getGui() const { return mGui; } - -MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } -MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } -MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } -MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } -MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } -MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } -MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } -MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } -MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } -MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } -MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } -MWGui::Console* WindowManager::getConsole() { return mConsole; } - -bool WindowManager::isAllowed (GuiWindow wnd) const -{ - return mAllowed & wnd; -} - -void WindowManager::allow (GuiWindow wnd) -{ - mAllowed = (GuiWindow)(mAllowed | wnd); - - if (wnd & GW_Inventory) + void WindowManager::setInteriorMapTexture(const int x, const int y) { - mBookWindow->setInventoryAllowed (true); - mScrollWindow->setInventoryAllowed (true); + mMap->setActiveCell(x,y, true); + mHud->setActiveCell(x,y, true); + } + + void WindowManager::setPlayerPos(const float x, const float y) + { + mMap->setPlayerPos(x,y); + mHud->setPlayerPos(x,y); + } + + void WindowManager::setPlayerDir(const float x, const float y) + { + mMap->setPlayerDir(x,y); + mHud->setPlayerDir(x,y); + } + + void WindowManager::setHMSVisibility(bool visible) + { + mHud->setHmsVisible (visible); + } + + void WindowManager::setMinimapVisibility(bool visible) + { + mHud->setMinimapVisible (visible); + } + + void WindowManager::toggleFogOfWar() + { + mMap->toggleFogOfWar(); + mHud->toggleFogOfWar(); + } + + void WindowManager::setFocusObject(const MWWorld::Ptr& focus) + { + mToolTips->setFocusObject(focus); + } + + void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) + { + mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y); + } + + void WindowManager::toggleFullHelp() + { + mToolTips->toggleFullHelp(); + } + + bool WindowManager::getFullHelp() const + { + return mToolTips->getFullHelp(); + } + + void WindowManager::setWeaponVisibility(bool visible) + { + mHud->setWeapVisible (visible); + } + + void WindowManager::setSpellVisibility(bool visible) + { + mHud->setSpellVisible (visible); + mHud->setEffectVisible (visible); + } + + void WindowManager::setMouseVisible(bool visible) + { + mCursor->setVisible(visible); + } + + void WindowManager::setDragDrop(bool dragDrop) + { + mToolTips->setEnabled(!dragDrop); + MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); + } + + void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) + { + std::string tag(_tag); + + std::string tokenToFind = "sCell="; + size_t tokenLength = tokenToFind.length(); + + if (tag.substr(0, tokenLength) == tokenToFind) + { + _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); + } + else + { + const ESM::GameSetting *setting = + MWBase::Environment::get().getWorld()->getStore().get().find(tag); + + if (setting && setting->mValue.getType()==ESM::VT_String) + _result = setting->mValue.getString(); + else + _result = tag; + } + } + + void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) + { + mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); + mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); + + bool changeRes = false; + bool windowRecreated = false; + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); + it != changed.end(); ++it) + { + if (it->first == "Video" && ( + it->second == "resolution x" + || it->second == "resolution y")) + { + changeRes = true; + } + else if (it->first == "Video" && it->second == "vsync") + windowRecreated = true; + else if (it->first == "HUD" && it->second == "crosshair") + mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); + else if (it->first == "GUI" && it->second == "subtitles") + mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); + } + + if (changeRes) + { + int x = Settings::Manager::getInt("resolution x", "Video"); + int y = Settings::Manager::getInt("resolution y", "Video"); + mHud->onResChange(x, y); + mConsole->onResChange(x, y); + mMenu->onResChange(x, y); + mSettingsWindow->center(); + mAlchemyWindow->center(); + mScrollWindow->center(); + mBookWindow->center(); + mQuickKeysMenu->center(); + mSpellBuyingWindow->center(); + mLoadingScreen->onResChange (x,y); + mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); + mInputBlocker->setSize(MyGUI::IntSize(x,y)); + } + if (windowRecreated) + { + mGuiManager->updateWindow (mRendering->getWindow ()); + mLoadingScreen->updateWindow (mRendering->getWindow ()); + } + } + + void WindowManager::pushGuiMode(GuiMode mode) + { + if (mode==GM_Inventory && mAllowed==GW_None) + return; + + + // If this mode already exists somewhere in the stack, just bring it to the front. + if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + { + mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + } + + mGuiModes.push_back(mode); + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); + } + + void WindowManager::popGuiMode() + { + if (!mGuiModes.empty()) + mGuiModes.pop_back(); + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); + } + + void WindowManager::removeGuiMode(GuiMode mode) + { + std::vector::iterator it = mGuiModes.begin(); + while (it != mGuiModes.end()) + { + if (*it == mode) + it = mGuiModes.erase(it); + else + ++it; + } + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); + } + + void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) + { + mHud->setSelectedSpell(spellId, successChancePercent); + + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + mSpellWindow->setTitle(spell->mName); + } + + void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() + .find(MWWorld::Class::get(item).getEnchantment(item)); + + int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; + mHud->setSelectedEnchantItem(item, chargePercent); + mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); + } + + void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) + { + int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; + mHud->setSelectedWeapon(item, durabilityPercent); + mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); + } + + void WindowManager::unsetSelectedSpell() + { + mHud->unsetSelectedSpell(); + mSpellWindow->setTitle("#{sNone}"); + } + + void WindowManager::unsetSelectedWeapon() + { + mHud->unsetSelectedWeapon(); + mInventoryWindow->setTitle("#{sSkillHandtohand}"); + } + + void WindowManager::getMousePosition(int &x, int &y) + { + const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); + x = pos.left; + y = pos.top; + } + + void WindowManager::getMousePosition(float &x, float &y) + { + const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); + x = pos.left; + y = pos.top; + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + x /= viewSize.width; + y /= viewSize.height; + } + + bool WindowManager::getWorldMouseOver() + { + return mHud->getWorldMouseOver(); + } + + void WindowManager::executeInConsole (const std::string& path) + { + mConsole->executeFile (path); + } + + void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) + { + mFPS = fps; + mTriangleCount = triangleCount; + mBatchCount = batchCount; + } + + MyGUI::Gui* WindowManager::getGui() const { return mGui; } + + MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } + MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } + MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } + MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } + MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } + MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } + MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } + MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } + MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } + MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } + MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } + MWGui::Console* WindowManager::getConsole() { return mConsole; } + + bool WindowManager::isAllowed (GuiWindow wnd) const + { + return mAllowed & wnd; + } + + void WindowManager::allow (GuiWindow wnd) + { + mAllowed = (GuiWindow)(mAllowed | wnd); + + if (wnd & GW_Inventory) + { + mBookWindow->setInventoryAllowed (true); + mScrollWindow->setInventoryAllowed (true); + } + + updateVisible(); + } + + void WindowManager::disallowAll() + { + mAllowed = GW_None; + + mBookWindow->setInventoryAllowed (false); + mScrollWindow->setInventoryAllowed (false); + + updateVisible(); + } + + void WindowManager::toggleVisible (GuiWindow wnd) + { + mShown = (mShown & wnd) ? (GuiWindow) (mShown & ~wnd) : (GuiWindow) (mShown | wnd); + updateVisible(); + } + + bool WindowManager::isGuiMode() const + { + return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); + } + + bool WindowManager::isConsoleMode() const + { + if (!mGuiModes.empty() && mGuiModes.back()==GM_Console) + return true; + return false; + } + + MWGui::GuiMode WindowManager::getMode() const + { + if (mGuiModes.empty()) + return GM_None; + return mGuiModes.back(); + } + + std::map > WindowManager::getPlayerSkillValues() + { + return mPlayerSkillValues; + } + + std::map > WindowManager::getPlayerAttributeValues() + { + return mPlayerAttributes; + } + + WindowManager::SkillList WindowManager::getPlayerMinorSkills() + { + return mPlayerMinorSkills; + } + + WindowManager::SkillList WindowManager::getPlayerMajorSkills() + { + return mPlayerMajorSkills; + } + + void WindowManager::disallowMouse() + { + mInputBlocker->setVisible (true); + } + + void WindowManager::allowMouse() + { + mInputBlocker->setVisible (!isGuiMode ()); + } + + void WindowManager::notifyInputActionBound () + { + mSettingsWindow->updateControlsBox (); + allowMouse(); + } + + void WindowManager::showCrosshair (bool show) + { + mHud->setCrosshairVisible (show && mCrosshairEnabled); + } + + void WindowManager::activateQuickKey (int index) + { + mQuickKeysMenu->activateQuickKey(index); + } + + bool WindowManager::getSubtitlesEnabled () + { + return mSubtitlesEnabled; + } + + void WindowManager::toggleHud () + { + mHudEnabled = !mHudEnabled; + mHud->setVisible (mHudEnabled); + } + + void WindowManager::setLoadingProgress (const std::string& stage, int depth, int current, int total) + { + mLoadingScreen->setLoadingProgress (stage, depth, current, total); + } + + void WindowManager::loadingDone () + { + mLoadingScreen->loadingDone (); + } + + bool WindowManager::getPlayerSleeping () + { + return mWaitDialog->getSleeping(); + } + + void WindowManager::wakeUpPlayer() + { + mWaitDialog->wakeUp(); + } + + void WindowManager::addVisitedLocation(const std::string& name, int x, int y) + { + mMap->addVisitedLocation (name, x, y); + } + + void WindowManager::startSpellMaking(MWWorld::Ptr actor) + { + mSpellCreationDialog->startSpellMaking (actor); + } + + void WindowManager::startEnchanting (MWWorld::Ptr actor) + { + mEnchantingDialog->startEnchanting (actor); + } + + void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) + { + mEnchantingDialog->startSelfEnchanting(soulgem); + } + + void WindowManager::startTraining(MWWorld::Ptr actor) + { + mTrainingWindow->startTraining(actor); + } + + void WindowManager::startRepair(MWWorld::Ptr actor) + { + mMerchantRepair->startRepair(actor); + } + + void WindowManager::startRepairItem(MWWorld::Ptr item) + { + mRepair->startRepairItem(item); + } + + const Translation::Storage& WindowManager::getTranslationDataStorage() const + { + return mTranslationDataStorage; + } + + void WindowManager::showCompanionWindow(MWWorld::Ptr actor) + { + mCompanionWindow->open(actor); + } + + void WindowManager::changePointer(const std::string &name) + { + mCursor->onCursorChange(name); + } + + void WindowManager::showSoulgemDialog(MWWorld::Ptr item) + { + mSoulgemDialog->show(item); + } + + void WindowManager::frameStarted (float dt) + { + mInventoryWindow->doRenderUpdate (); } - updateVisible(); -} - -void WindowManager::disallowAll() -{ - mAllowed = GW_None; - - mBookWindow->setInventoryAllowed (false); - mScrollWindow->setInventoryAllowed (false); - - updateVisible(); -} - -void WindowManager::toggleVisible (GuiWindow wnd) -{ - mShown = (mShown & wnd) ? (GuiWindow) (mShown & ~wnd) : (GuiWindow) (mShown | wnd); - updateVisible(); -} - -bool WindowManager::isGuiMode() const -{ - return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); -} - -bool WindowManager::isConsoleMode() const -{ - if (!mGuiModes.empty() && mGuiModes.back()==GM_Console) - return true; - return false; -} - -MWGui::GuiMode WindowManager::getMode() const -{ - if (mGuiModes.empty()) - return GM_None; - return mGuiModes.back(); -} - -std::map > WindowManager::getPlayerSkillValues() -{ - return mPlayerSkillValues; -} - -std::map > WindowManager::getPlayerAttributeValues() -{ - return mPlayerAttributes; -} - -WindowManager::SkillList WindowManager::getPlayerMinorSkills() -{ - return mPlayerMinorSkills; -} - -WindowManager::SkillList WindowManager::getPlayerMajorSkills() -{ - return mPlayerMajorSkills; -} - -void WindowManager::disallowMouse() -{ - mInputBlocker->setVisible (true); -} - -void WindowManager::allowMouse() -{ - mInputBlocker->setVisible (!isGuiMode ()); -} - -void WindowManager::notifyInputActionBound () -{ - mSettingsWindow->updateControlsBox (); - allowMouse(); -} - -void WindowManager::showCrosshair (bool show) -{ - mHud->setCrosshairVisible (show && mCrosshairEnabled); -} - -void WindowManager::activateQuickKey (int index) -{ - mQuickKeysMenu->activateQuickKey(index); -} - -bool WindowManager::getSubtitlesEnabled () -{ - return mSubtitlesEnabled; -} - -void WindowManager::toggleHud () -{ - mHudEnabled = !mHudEnabled; - mHud->setVisible (mHudEnabled); -} - -void WindowManager::setLoadingProgress (const std::string& stage, int depth, int current, int total) -{ - mLoadingScreen->setLoadingProgress (stage, depth, current, total); -} - -void WindowManager::loadingDone () -{ - mLoadingScreen->loadingDone (); -} - -bool WindowManager::getPlayerSleeping () -{ - return mWaitDialog->getSleeping(); -} - -void WindowManager::wakeUpPlayer() -{ - mWaitDialog->wakeUp(); -} - -void WindowManager::addVisitedLocation(const std::string& name, int x, int y) -{ - mMap->addVisitedLocation (name, x, y); -} - -void WindowManager::startSpellMaking(MWWorld::Ptr actor) -{ - mSpellCreationDialog->startSpellMaking (actor); -} - -void WindowManager::startEnchanting (MWWorld::Ptr actor) -{ - mEnchantingDialog->startEnchanting (actor); -} - -void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) -{ - mEnchantingDialog->startSelfEnchanting(soulgem); -} - -void WindowManager::startTraining(MWWorld::Ptr actor) -{ - mTrainingWindow->startTraining(actor); -} - -void WindowManager::startRepair(MWWorld::Ptr actor) -{ - mMerchantRepair->startRepair(actor); -} - -void WindowManager::startRepairItem(MWWorld::Ptr item) -{ - mRepair->startRepairItem(item); -} - -const Translation::Storage& WindowManager::getTranslationDataStorage() const -{ - return mTranslationDataStorage; -} - -void WindowManager::showCompanionWindow(MWWorld::Ptr actor) -{ - mCompanionWindow->open(actor); -} - -void WindowManager::changePointer(const std::string &name) -{ - mCursor->onCursorChange(name); -} - -void WindowManager::showSoulgemDialog(MWWorld::Ptr item) -{ - mSoulgemDialog->show(item); -} - -void WindowManager::frameStarted (float dt) -{ - mInventoryWindow->doRenderUpdate (); } diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 53ba1b9fd6..e5a94fc721 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -2,25 +2,26 @@ #include "exposedwindow.hpp" -using namespace MWGui; - -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) - : WindowBase(parLayout), mPinned(false), mVisible(false) +namespace MWGui { - ExposedWindow* window = static_cast(mMainWidget); - mPinButton = window->getSkinWidget ("Button"); + WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) + : WindowBase(parLayout), mPinned(false), mVisible(false) + { + ExposedWindow* window = static_cast(mMainWidget); + mPinButton = window->getSkinWidget ("Button"); - mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); -} - -void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) -{ - mPinned = !mPinned; - - if (mPinned) - mPinButton->changeWidgetSkin ("PinDown"); - else - mPinButton->changeWidgetSkin ("PinUp"); - - onPinToggled(); + mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); + } + + void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) + { + mPinned = !mPinned; + + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); + + onPinToggled(); + } } From 3c5e4ceefd87140156bfa87c314242baef30676e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 16:46:32 +0200 Subject: [PATCH 1097/1483] Workaround for ambiguous "Chargen_plank" ID in chargen script (one at -22,16 and one at -2,-9) --- apps/openmw/mwworld/store.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index f69f606b45..fb3f8c4826 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -415,8 +415,18 @@ namespace MWWorld } }; - typedef std::map DynamicInt; - typedef std::map, ESM::Cell> DynamicExt; + struct DynamicExtCmp + { + bool operator()(const std::pair &left, const std::pair &right) const { + if (left.first == right.first) { + return left.second < right.second; + } + return left.first < right.first; + } + }; + + typedef std::map DynamicInt; + typedef std::map, ESM::Cell, DynamicExtCmp> DynamicExt; DynamicInt mInt; DynamicExt mExt; From b34caccd2ec90a582e4732d29fb1fc7a10a86e92 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 16:46:38 +0200 Subject: [PATCH 1098/1483] Fix moving NPCs not getting their collision box moved --- libs/openengine/bullet/physic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 524f57c1c4..eaeae7dc39 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -511,8 +511,8 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { - // This isn't needed as there are no dynamic objects at this point - //dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + // This seems to be needed for character controller objects + dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); if(isDebugCreated) { mDebugDrawer->step(); From c753eb4c287729759e897ef35fdd6b36b3acf429 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 18 Apr 2013 18:35:01 +0100 Subject: [PATCH 1099/1483] another way to do pathfinding. Slightly less powerfull algorithme in theory, but morrowind pathgrids are so simple it shouldn't be a problem. Hope it solves the bug for KittyCat --- apps/openmw/mwmechanics/pathfinding.cpp | 35 ++++++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 7c22e54701..2f27d25f8a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -1,5 +1,5 @@ #include "pathfinding.hpp" -#include +#include #include #include "boost/tuple/tuple.hpp" #include "OgreMath.h" @@ -55,7 +55,7 @@ namespace struct found_path {}; - class goalVisited : public boost::default_astar_visitor + /*class goalVisited : public boost::default_astar_visitor { public: goalVisited(PointID goal) : mGoal(goal) {} @@ -69,7 +69,7 @@ namespace PointID mGoal; }; - class DistanceHeuristic : public boost::astar_heuristic + class DistanceHeuristic : public boost::atasr_heuristic { public: DistanceHeuristic(const PathGridGraph & l, PointID goal) @@ -87,11 +87,23 @@ namespace private: const PathGridGraph & mGraph; PointID mGoal; - }; -} + };*/ + + class goalVisited : public boost::default_dijkstra_visitor + { + public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } + private: + PointID mGoal; + }; + -namespace MWMechanics -{ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; @@ -126,13 +138,12 @@ namespace MWMechanics std::list shortest_path; try { - boost::astar_search + boost::dijkstra_shortest_paths ( graph, start, - DistanceHeuristic(graph,end), boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); + ); } catch(found_path fg) { for(PointID v = end;; v = p[v]) { @@ -146,6 +157,10 @@ namespace MWMechanics //end of helpers functions +} + +namespace MWMechanics +{ PathFinder::PathFinder() { mIsPathConstructed = false; From f9deb593d1f5d6baba89b57cc8f5f3ba544917a6 Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 18 Apr 2013 21:37:58 +0200 Subject: [PATCH 1100/1483] Bugfix #578 --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d34c4b97f5..66d20e662c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -548,7 +548,7 @@ namespace MWMechanics float bribeMod; if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->getFloat(); - if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); + else if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); else bribeMod = gmst.find("fBribe1000Mod")->getFloat(); float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; From 3b3a052f4f7592b756583a0bc7fdadfe04b5a920 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Apr 2013 22:36:48 +0200 Subject: [PATCH 1101/1483] increased version number --- CMakeLists.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6a1017906..9f12b11fda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 22) +set (OPENMW_VERSION_MINOR 23) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") diff --git a/readme.txt b/readme.txt index 8edb0c4b31..9bce063fa2 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.22.0 +Version: 0.23.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From 257f9403660e82f3fed9231c6784429b13fdea38 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Apr 2013 22:50:04 +0200 Subject: [PATCH 1102/1483] updated changelog --- readme.txt | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/readme.txt b/readme.txt index 9bce063fa2..5f38457765 100644 --- a/readme.txt +++ b/readme.txt @@ -94,6 +94,65 @@ Allowed options: CHANGELOG +0.23.0 + +Bug #522: Player collides with placeable items +Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open +Bug #561: Tooltip word wrapping delay +Bug #578: Bribing works incorrectly +Bug #601: PositionCell fails on negative coordinates +Bug #606: Some NPCs hairs not rendered with Better Heads addon +Bug #609: Bad rendering of bone boots +Bug #613: Messagebox causing assert to fail +Bug #631: Segfault on shutdown +Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard +Bug #635: Scale NPCs depending on race +Bug #643: Dialogue Race select function is inverted +Bug #646: Twohanded weapons don't work properly +Bug #654: Crash when dropping objects without a collision shape +Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell +Bug #660: "g" in "change" cut off in Race Menu +Bug #661: Arrille sells me the key to his upstairs room +Bug #662: Day counter starts at 2 instead of 1 +Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur +Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window. +Bug #666: Looking up/down problem +Bug #667: Active effects border visible during loading +Bug #669: incorrect player position at new game start +Bug #670: race selection menu: sex, face and hair left button not totally clickable +Bug #671: new game: player is naked +Bug #674: buying or selling items doesn't change amount of gold +Bug #675: fatigue is not set to its maximum when starting a new game +Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly +Bug #680: different gold coins in Tel Mara +Bug #682: Race menu ignores playable flag for some hairs and faces +Bug #685: Script compiler does not accept ":" after a function name +Bug #688: dispose corpse makes cross-hair to disappear +Bug #691: Auto equipping ignores equipment conditions +Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder +Bug #696: Draugr incorrect head offset +Bug #697: Sail transparency issue +Bug #700: "On the rocks" mod does not load its UV coordinates correctly. +Bug #702: Some race mods don't work +Bug #711: Crash during character creation +Bug #715: Growing Tauryon +Feature #55/657: Item Repairing +Feature #62/87: Enchanting +Feature #99: Pathfinding +Feature #104: AI Package: Travel +Feature #129: Levelled items +Feature #204: Texture animations +Feature #239: Fallback-Settings +Feature #535: Console object selection improvements +Feature #629: Add levelup description in levelup layout dialog +Feature #630: Optional format subrecord in (tes3) header +Feature #641: Armor rating +Feature #645: OnDeath script function +Feature #683: Companion item UI +Feature #698: Basic Particles +Task #648: Split up components/esm/loadlocks +Task #695: mwgui cleanup + 0.22.0 Bug #311: Potential infinite recursion in script compiler From ef9afeb53e5b48fd3a903a1e26a8a869ef89e7ee Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 23:51:43 +0200 Subject: [PATCH 1103/1483] Auto calculate attributes if there are not specified in the NPC record --- apps/openmw/mwclass/npc.cpp | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7cda87bb15..ea49ae4a4c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,67 @@ namespace { return new CustomData (*this); } + + void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) + { + // race bonus + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mRace); + + bool male = (npc->mFlags & ESM::NPC::Female) == 0; + + int level = creatureStats.getLevel(); + + for (int i=0; imData.mAttributeValues[i]; + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); + } + + // class bonus + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mClass); + + for (int i=0; i<2; ++i) + { + int attribute = class_->mData.mAttribute[i]; + if (attribute>=0 && attribute<8) + { + creatureStats.getAttribute(attribute).setBase ( + creatureStats.getAttribute(attribute).getBase() + 10); + } + } + + // skill bonus + for (int attribute=0; attributegetStore().get().find(j); + + if (skill->mData.mAttribute != attribute) + continue; + + // is this a minor or major skill? + float add=0.2; + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][0] == j) + add=0.5; + } + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][1] == j) + add=1.0; + } + modifierSum += add; + } + creatureStats.getAttribute(attribute).setBase ( std::min(creatureStats.getAttribute(attribute).getBase() + + static_cast((level-1) * modifierSum+0.5), 100) ); + } + } } namespace MWClass @@ -126,15 +187,14 @@ namespace MWClass } else { - for (int i=0; i<8; ++i) - data->mCreatureStats.getAttribute (i).set (10); - for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + + autoCalculateAttributes(ref->mBase, data->mCreatureStats); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 92e06cebf3f6cbd0930529ab026221c5ff2c69ca Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 00:26:36 +0200 Subject: [PATCH 1104/1483] last minute change to changelog --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 5f38457765..d5a5dcc183 100644 --- a/readme.txt +++ b/readme.txt @@ -136,6 +136,7 @@ Bug #700: "On the rocks" mod does not load its UV coordinates correctly. Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon +Bug #725: Auto calculate stats Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From e92897526c9fb6bc8fb1acf836b7b841374cc919 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 01:33:04 +0200 Subject: [PATCH 1105/1483] Only use the shader based mygui manager if the fixed pipeline is unavailable --- libs/openengine/gui/manager.cpp | 30 ++++++++++++++++++++++++++---- libs/openengine/gui/manager.hpp | 5 +++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index f9117586fe..a0a4ab0aea 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -559,6 +559,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool assert(mgr); mSceneMgr = mgr; + mShaderRenderManager = NULL; + mRenderManager = NULL; using namespace MyGUI; @@ -574,7 +576,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new MyGUI::ShaderBasedRenderManager(); + if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) + mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); + else + mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); @@ -582,7 +587,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool if (!theLogFile.empty()) LogManager::getInstance().createDefaultSource(theLogFile); - mRenderManager->initialise(wnd, mgr); + if (mShaderRenderManager) + mShaderRenderManager->initialise(wnd, mgr); + else + mRenderManager->initialise(wnd, mgr); mDataManager->initialise("General"); // Create GUI @@ -592,8 +600,16 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) { - mRenderManager->setRenderWindow (wnd); - mRenderManager->setActiveViewport(0); + if (mShaderRenderManager) + { + mShaderRenderManager->setRenderWindow (wnd); + mShaderRenderManager->setActiveViewport(0); + } + else + { + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); + } } void MyGUIManager::shutdown() @@ -606,6 +622,12 @@ void MyGUIManager::shutdown() delete mRenderManager; mRenderManager = NULL; } + if(mShaderRenderManager) + { + mShaderRenderManager->shutdown(); + delete mShaderRenderManager; + mShaderRenderManager = NULL; + } if(mDataManager) { mDataManager->shutdown(); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index eec867ff8b..9535f2a24e 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,6 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; + class OgreRenderManager; class ShaderBasedRenderManager; } @@ -25,12 +26,12 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::ShaderBasedRenderManager* mRenderManager; + MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mShaderRenderManager; Ogre::SceneManager* mSceneMgr; public: - MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL), mGui(NULL) {} MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) { setup(wnd,mgr,logging, logDir); From 50bb92beb349f340801923565db15c1c78832c38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 02:01:50 -0700 Subject: [PATCH 1106/1483] Use a method to set the visibility flags and render queue. --- apps/openmw/mwrender/activatoranimation.cpp | 24 +------------------ apps/openmw/mwrender/animation.cpp | 26 +++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/creatureanimation.cpp | 25 +------------------- apps/openmw/mwrender/npcanimation.cpp | 21 ++++------------- 5 files changed, 35 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 1f9a2e23c9..c3a3045c20 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -1,10 +1,5 @@ #include "activatoranimation.hpp" -#include -#include -#include -#include - #include "renderconst.hpp" #include "../mwbase/world.hpp" @@ -27,24 +22,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) const std::string name = "meshes\\"+ref->mBase->mModel; addObjectList(mPtr.getRefData().getBaseNode(), name, false); - const NifOgre::ObjectList &objlist = mObjectLists.back(); - for(size_t i = 0;i < objlist.mEntities.size();i++) - { - Ogre::Entity *ent = objlist.mEntities[i]; - ent->setVisibilityFlags(RV_Misc); - - for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = ent->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < objlist.mParticles.size();i++) - { - Ogre::ParticleSystem *part = objlist.mParticles[i]; - part->setVisibilityFlags(RV_Misc); - part->setRenderQueueGroup(RQG_Alpha); - } + setRenderProperties(mObjectLists.back(), RV_Misc, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 11876a2473..8e5bd01081 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -150,6 +152,30 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b mCurrentControllers = &objlist.mControllers; } +void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) +{ + for(size_t i = 0;i < objlist.mEntities.size();i++) + { + Ogre::Entity *ent = objlist.mEntities[i]; + if(visflags != 0) + ent->setVisibilityFlags(visflags); + + for(unsigned int j = 0;j < ent->getNumSubEntities();++j) + { + Ogre::SubEntity* subEnt = ent->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? transqueue : solidqueue); + } + } + for(size_t i = 0;i < objlist.mParticles.size();i++) + { + Ogre::ParticleSystem *part = objlist.mParticles[i]; + if(visflags != 0) + part->setVisibilityFlags(visflags); + // TODO: Check particle material for actual transparency + part->setRenderQueueGroup(transqueue); + } +} + Ogre::Node *Animation::getNode(const std::string &name) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index f8ddceeaa3..db2195c342 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -85,6 +85,8 @@ protected: void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); + static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index a48b8da9f8..51632b2ee1 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,10 +1,5 @@ #include "creatureanimation.hpp" -#include -#include -#include -#include - #include "renderconst.hpp" #include "../mwbase/world.hpp" @@ -30,25 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); addObjectList(mPtr.getRefData().getBaseNode(), model, false); - - const NifOgre::ObjectList &objlist = mObjectLists.back(); - for(size_t i = 0;i < objlist.mEntities.size();i++) - { - Ogre::Entity *ent = objlist.mEntities[i]; - ent->setVisibilityFlags(RV_Actors); - - for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = ent->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < objlist.mParticles.size();i++) - { - Ogre::ParticleSystem *part = objlist.mParticles[i]; - part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); - } + setRenderProperties(mObjectLists.back(), RV_Actors, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cea0225ef9..0b05b4ba66 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -361,25 +361,13 @@ void NpcAnimation::updateParts(bool forceupdate) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); - for(size_t i = 0;i < objects.mEntities.size();i++) - { - objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if(mVisibilityFlags != 0) - objects.mEntities[i]->setVisibilityFlags(mVisibilityFlags); + setRenderProperties(objects, mVisibilityFlags, RQG_Main, RQG_Alpha); - for(unsigned int j=0; j < objects.mEntities[i]->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = objects.mEntities[i]->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } + for(size_t i = 0;i < objects.mEntities.size();i++) + objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); for(size_t i = 0;i < objects.mParticles.size();i++) - { objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if(mVisibilityFlags != 0) - objects.mParticles[i]->setVisibilityFlags(mVisibilityFlags); - objects.mParticles[i]->setRenderQueueGroup(RQG_Alpha); - } + if(objects.mSkelBase) { Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); @@ -395,6 +383,7 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } + return objects; } From f13b0c884fa1eb4a93060a1722f45677bf458d08 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 14:41:26 +0200 Subject: [PATCH 1107/1483] hotfix for CharacterPreview destructor --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8396acaea8..41770d4891 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -21,13 +21,15 @@ namespace MWRender CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mSizeX(sizeX) - , mSizeY(sizeY) - , mName(name) + + : mSceneMgr (0) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) + , mName(name) + , mSizeX(sizeX) + , mSizeY(sizeY) { } @@ -88,16 +90,20 @@ namespace MWRender CharacterPreview::~CharacterPreview () { - //Ogre::TextureManager::getSingleton().remove(mName); - mSceneMgr->destroyCamera (mName); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneMgr) + { + //Ogre::TextureManager::getSingleton().remove(mName); + mSceneMgr->destroyAllCameras(); + delete mAnimation; + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + } } void CharacterPreview::rebuild() { assert(mAnimation); delete mAnimation; + mAnimation = 0; mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); From a8e3acd6c4db2c502e3f1de49bb054d53ba4ca5f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 17:57:22 +0200 Subject: [PATCH 1108/1483] Fix consecutive dialogue choices --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 9380ab76cd..220adf566a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -426,6 +426,7 @@ namespace MWDialogue void DialogueManager::questionAnswered (const std::string& answer) { + if (mChoiceMap.find(answer) != mChoiceMap.end()) { mChoice = mChoiceMap[answer]; @@ -442,6 +443,10 @@ namespace MWDialogue std::string text = info->mResponse; parseText (text); + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); @@ -449,9 +454,6 @@ namespace MWDialogue mLastDialogue = *info; } } - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; } updateTopics(); From 1051fa51a71f964fa55a73d054c558862ee95ed0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 15:07:08 -0700 Subject: [PATCH 1109/1483] Recognize NiFlipController --- components/nif/controller.hpp | 23 +++++++++++++++++++++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 1 + components/nif/recordptr.hpp | 1 + 4 files changed, 26 insertions(+) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index aa6a9ef4ff..011e0e4452 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -303,5 +303,28 @@ public: } }; +class NiFlipController : public Controller +{ +public: + int mTexSlot; + float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources + NiSourceTextureList mSources; + + void read(NIFStream *nif) + { + Controller::read(nif); + mTexSlot = nif->getUInt(); + /*unknown=*/nif->getUInt();/*0?*/ + mDelta = nif->getFloat(); + mSources.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + mSources.post(nif); + } +}; + } // Namespace #endif diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 2c4f3506ea..a66bd99db5 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -235,6 +235,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiMaterialColorController", &construct , RC_NiMaterialColorController }, { "NiBSPArrayController", &construct , RC_NiBSPArrayController }, { "NiParticleSystemController", &construct , RC_NiParticleSystemController }, + { "NiFlipController", &construct , RC_NiFlipController }, { "NiAmbientLight", &construct , RC_NiLight }, { "NiDirectionalLight", &construct , RC_NiLight }, { "NiTextureEffect", &construct , RC_NiTextureEffect }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 97b10503e8..3f852ed837 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -60,6 +60,7 @@ enum RecordType RC_NiMaterialColorController, RC_NiBSPArrayController, RC_NiParticleSystemController, + RC_NiFlipController, RC_NiBSAnimationNode, RC_NiLight, RC_NiTextureEffect, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index c5bafea124..2ecde7f60e 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -163,6 +163,7 @@ typedef RecordPtrT NiAutoNormalParticlesDataPtr; typedef RecordListT NodeList; typedef RecordListT PropertyList; +typedef RecordListT NiSourceTextureList; } // Namespace #endif From f37a71f02584dddfe50655dea4689aaea4bf89f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 23:56:47 -0700 Subject: [PATCH 1110/1483] Use a separate method to build node-based controllers --- components/nifogre/ogrenifloader.cpp | 77 +++++++++++++++------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index c5cc45ae9f..21acfca0fb 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -575,6 +575,44 @@ class NIFObjectLoader } + static void createNodeControllers(const std::string &name, Nif::ControllerPtr ctrl, ObjectList &objectlist, int animflags) + { + do { + if(ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + else if(ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + } + ctrl = ctrl->next; + } while(!ctrl.empty()); + } + + static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags, int animflags, int partflags) @@ -613,6 +651,9 @@ class NIFObjectLoader e = e->extra; } + if(!node->controller.empty()) + createNodeControllers(name, node->controller, objectlist, animflags); + if(node->recType == Nif::RC_NiCamera) { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); @@ -620,42 +661,6 @@ class NIFObjectLoader objectlist.mCameras.push_back(trgtbone); } - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if(ctrl->recType == Nif::RC_NiKeyframeController) - { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - } - ctrl = ctrl->next; - } - if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { createEntity(name, group, sceneMgr, objectlist, node, flags, animflags); From ace7d647e5af1182a972505bb6f3aa1a01ee16d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Apr 2013 15:35:19 -0700 Subject: [PATCH 1111/1483] Add a method to apply a NodeTargetValue-based controller to a specified node. --- components/nifogre/ogrenifloader.cpp | 147 +++++++++++++++------------ components/nifogre/ogrenifloader.hpp | 2 + 2 files changed, 82 insertions(+), 67 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 21acfca0fb..90147a43bc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -104,7 +104,7 @@ public: private: std::vector mData; - virtual bool calculate(Ogre::Real time) + bool calculate(Ogre::Real time) const { if(mData.size() == 0) return true; @@ -144,16 +144,21 @@ public: , mData(data->mVis) { } + virtual void applyToNode(Ogre::Node *node, float time) const + { + bool vis = calculate(time); + setVisible(node, vis); + } + virtual Ogre::Real getValue() const { // Should not be called - return 1.0f; + return 0.0f; } virtual void setValue(Ogre::Real time) { - bool vis = calculate(time); - setVisible(mNode, vis); + Value::applyToNode(mNode, time); } }; @@ -170,6 +175,66 @@ public: Nif::Vector3KeyList mTranslations; Nif::FloatKeyList mScales; + static float interpKey(const Nif::FloatKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } + + static Ogre::Vector3 interpKey(const Nif::Vector3KeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::Vector3KeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } + + static Ogre::Quaternion interpKey(const Nif::QuaternionKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::QuaternionKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue); + } + return Ogre::Quaternion(); + } + public: Value(Ogre::Node *target, const Nif::NiKeyframeData *data) : NodeTargetValue(target) @@ -178,6 +243,16 @@ public: , mScales(data->mScales) { } + virtual void applyToNode(Ogre::Node *node, float time) const + { + if(mRotations.mKeys.size() > 0) + node->setOrientation(interpKey(mRotations.mKeys, time)); + if(mTranslations.mKeys.size() > 0) + node->setPosition(interpKey(mTranslations.mKeys, time)); + if(mScales.mKeys.size() > 0) + node->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); + } + virtual Ogre::Real getValue() const { // Should not be called @@ -186,69 +261,7 @@ public: virtual void setValue(Ogre::Real time) { - if(mRotations.mKeys.size() > 0) - { - if(time <= mRotations.mKeys.front().mTime) - mNode->setOrientation(mRotations.mKeys.front().mValue); - else if(time >= mRotations.mKeys.back().mTime) - mNode->setOrientation(mRotations.mKeys.back().mValue); - else - { - Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); - for(;iter != mRotations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); - break; - } - } - } - if(mTranslations.mKeys.size() > 0) - { - if(time <= mTranslations.mKeys.front().mTime) - mNode->setPosition(mTranslations.mKeys.front().mValue); - else if(time >= mTranslations.mKeys.back().mTime) - mNode->setPosition(mTranslations.mKeys.back().mValue); - else - { - Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); - for(;iter != mTranslations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::Vector3KeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); - break; - } - } - } - if(mScales.mKeys.size() > 0) - { - if(time <= mScales.mKeys.front().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); - else if(time >= mScales.mKeys.back().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); - else - { - Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); - for(;iter != mScales.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); - break; - } - } - } + Value::applyToNode(mNode, time); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index e3bb550640..b53815fa0f 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -85,6 +85,8 @@ public: NodeTargetValue(Ogre::Node *target) : mNode(target) { } + virtual void applyToNode(Ogre::Node *node, float time) const = 0; + void setNode(Ogre::Node *target) { mNode = target; } Ogre::Node *getNode() const From 835ff8eb1eb36bc16cffaca85343ee86d1533275 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Apr 2013 17:13:27 -0700 Subject: [PATCH 1112/1483] Avoid creating an AnimationValue per ObjectList --- apps/openmw/mwrender/animation.cpp | 6 +++--- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8e5bd01081..56b601727a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -32,7 +32,8 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mPtr(ptr) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + , mPtr(ptr) , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) @@ -70,7 +71,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b mInsert = node->createChildSceneNode(); assert(mInsert); } - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : NifOgre::Loader::createObjectBase(mInsert, model)); @@ -145,7 +145,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b for(size_t i = 0;i < objlist.mControllers.size();i++) { if(objlist.mControllers[i].getSource().isNull()) - objlist.mControllers[i].setSource(ctrlval); + objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } if(!mCurrentControllers || (*mCurrentControllers).size() == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index db2195c342..d3cb6bebb7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,6 +38,7 @@ protected: mAnimation->mCurrentTime = value; } }; + Ogre::SharedPtr > mAnimationBaseValuePtr; MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; From 19325f9d40944df8c6b312d309469e59e3c6c520 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 21 Apr 2013 11:41:09 -0700 Subject: [PATCH 1113/1483] fixed the type of iterator uses in MWWorld::Store The containers type used to declare some iterators was not an exact match for the type of the container the iterator was being initialized from. This was causing build failure on windows. --- apps/openmw/mwworld/store.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fb3f8c4826..2bd61c2b02 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -475,7 +475,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -493,7 +493,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -534,7 +534,7 @@ namespace MWWorld void setUp() { //typedef std::vector::iterator Iterator; - typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef DynamicExt::iterator ExtIterator; typedef std::map::iterator IntIterator; //std::sort(mInt.begin(), mInt.end(), RecordCmp()); From 8bf1149cec0da1e8f7c59089c01b8804c9897cf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Apr 2013 21:24:48 +0200 Subject: [PATCH 1114/1483] Fix activation not working sometimes The current player cell was only being updated when the reference was not empty, causing it to incorrectly detect a cell change the first time something was activated in a newly visited cell, immediately closing the opened dialogue again. --- apps/openmw/mwgui/referenceinterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 66e036d929..86a85be18e 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -18,17 +18,17 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - if (mPtr.isEmpty()) - return; - MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) - || mPtr.getRefData().getCount() == 0) + || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) { - mPtr = MWWorld::Ptr(); - onReferenceUnavailable(); + if (!mPtr.isEmpty()) + { + mPtr = MWWorld::Ptr(); + onReferenceUnavailable(); + } } mCurrentPlayerCell = playerCell; From d7c9df16f81ceebc7ee5da0b5242d33814a7e85e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 18:32:34 -0700 Subject: [PATCH 1115/1483] Store the current animation group --- apps/openmw/mwrender/animation.cpp | 3 ++- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 56b601727a..ea27cbb5e1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -441,9 +441,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; - mAnimVelocity = 0.0f; + mAnimVelocity = 0.0f; if(mNonAccumRoot) calcAnimVelocity(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d3cb6bebb7..472a6289c9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -53,6 +53,7 @@ protected: Ogre::Vector3 mLastPosition; Ogre::Animation *mCurrentAnim; + std::string mCurrentGroup; std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; From 6c85d6763aec95b2f3367fea90437f4e818042e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 18:38:25 -0700 Subject: [PATCH 1116/1483] Pass "loop stop" to the character controller --- apps/openmw/mwmechanics/character.cpp | 9 +++++++++ apps/openmw/mwrender/animation.cpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 02a5aa1006..16d8115284 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -150,6 +150,15 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::markerEvent(float time, const std::string &evt) { + if(evt == "loop stop") + { + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start", "stop", false); + } + return; + } if(evt == "stop") { if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ea27cbb5e1..68fae99ddf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -409,10 +409,10 @@ bool Animation::handleEvent(float time, const std::string &evt) reset("loop start"); if(mCurrentTime >= time) return false; + return true; } - return true; } - if(evt == "stop") + else if(evt == "stop") { if(mLooping) { From 7d59340ed6c27b4b895e9e9b7200c35bc612714c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 22:13:49 -0700 Subject: [PATCH 1117/1483] Don't clip out the group name from the textkeys --- apps/openmw/mwrender/animation.cpp | 39 +++++++++++++++++++----------- components/nifogre/skeleton.cpp | 12 +-------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 68fae99ddf..2f2ffccb5e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -243,14 +243,16 @@ void Animation::calcAnimVelocity() if(track && track->getNumKeyFrames() > 1) { + const std::string loopstart = mCurrentGroup+": loop start"; + const std::string loopstop = mCurrentGroup+": loop stop"; float loopstarttime = 0.0f; float loopstoptime = mCurrentAnim->getLength(); NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); while(keyiter != mCurrentKeys->end()) { - if(keyiter->second == "loop start") + if(keyiter->second == loopstart) loopstarttime = keyiter->first; - else if(keyiter->second == "loop stop") + else if(keyiter->second == loopstop) { loopstoptime = keyiter->first; break; @@ -383,12 +385,6 @@ void Animation::reset(const std::string &start, const std::string &stop) bool Animation::handleEvent(float time, const std::string &evt) { - if(evt == "start" || evt == "loop start") - { - /* Do nothing */ - return true; - } - if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -402,21 +398,36 @@ bool Animation::handleEvent(float time, const std::string &evt) return true; } - if(evt == "loop stop") + if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || + evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + { + // Not ours + return true; + } + size_t off = mCurrentGroup.size()+2; + size_t len = evt.size() - off; + + if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) + { + /* Do nothing */ + return true; + } + + if(evt.compare(off, len, "loop stop") == 0) { if(mLooping) { - reset("loop start"); + reset(mCurrentGroup+": loop start"); if(mCurrentTime >= time) return false; return true; } } - else if(evt == "stop") + else if(evt.compare(off, len, "stop") == 0) { if(mLooping) { - reset("loop start"); + reset(mCurrentGroup+": loop start"); if(mCurrentTime >= time) return false; return true; @@ -424,7 +435,7 @@ bool Animation::handleEvent(float time, const std::string &evt) // fall-through } if(mController) - mController->markerEvent(time, evt); + mController->markerEvent(time, evt.substr(off)); return true; } @@ -455,7 +466,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!found) throw std::runtime_error("Failed to find animation "+groupname); - reset(start, stop); + reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); setLooping(loop); mPlaying = true; } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 75bc907152..5eb0436143 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -282,17 +282,7 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - TextKeyMap::const_iterator insiter(keyiter); - TextKeyMap groupkeys; - do { - sep = insiter->second.find(':'); - if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); - else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first, insiter->second)); - } while(insiter++ != lastkeyiter); - + TextKeyMap groupkeys(keyiter, ++lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 2345b5e8b3d7ebe69ef901098ac9d4603973ad09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 22:56:40 -0700 Subject: [PATCH 1118/1483] Avoid storing text keys for each animation --- apps/openmw/mwrender/animation.cpp | 15 +++------------ apps/openmw/mwrender/animation.hpp | 1 - components/nifogre/ogrenifloader.hpp | 2 ++ components/nifogre/skeleton.cpp | 7 +------ 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2f2ffccb5e..d51a30a770 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -121,24 +121,15 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b Ogre::Bone *bone = boneiter.getNext(); Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; + if(data.isEmpty()) continue; + objlist.mTextKeys[bone->getHandle()] = Ogre::any_cast(data); if(!mNonAccumRoot) { mAccumRoot = mInsert; mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); } - for(int i = 0;i < skel->getNumAnimations();i++) - { - Ogre::Animation *anim = skel->getAnimation(i); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); - if(!groupdata.isEmpty()) - mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); - } - break; } } @@ -451,7 +442,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con { Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); mCurrentAnim = skel->getAnimation(groupname); - mCurrentKeys = &mTextKeys[groupname]; + mCurrentKeys = &iter->mTextKeys.begin()->second; mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 472a6289c9..b60bd21a85 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -46,7 +46,6 @@ protected: Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; std::vector mObjectLists; - std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index b53815fa0f..8e220ea38d 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -50,6 +50,8 @@ struct ObjectList { // bones in the mSkelBase which are NiCamera nodes. std::vector mCameras; + std::map mTextKeys; + std::vector > mControllers; ObjectList() : mSkelBase(0) diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 5eb0436143..3660be81bd 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -193,6 +193,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); animroot = bone; + bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(textkeys)); } e = e->extra; } @@ -255,9 +256,6 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) return; } - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); - bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); - std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) @@ -281,9 +279,6 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) } buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - - TextKeyMap groupkeys(keyiter, ++lastkeyiter); - bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 56b871e362724008c8bd4c5a686f63ce730f2a36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Apr 2013 07:57:53 +0200 Subject: [PATCH 1119/1483] Rank condition should always fail if NPC is not in a faction --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 78969ffd0b..52c7bd4f34 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -73,6 +73,11 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (iter->second < info.mData.mRank) return false; } + else if (info.mData.mRank != -1) + { + // if there is a rank condition, but the NPC is not in a faction, always fail + return false; + } // Gender if (!isCreature) From a3511c62cf2c120636b4960f34f0a4973292d1c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 00:01:30 -0700 Subject: [PATCH 1120/1483] Don't store textkeys in user object bindings It's a bit unwieldy to have them stored in the 'skeleton master' instead of the skeleton instance. And although the text keys are extracted for each created instance now, this shouldn't be much worse than the multimap copying going on before. Plus, proper serialization can help for future optimizations. --- apps/openmw/mwrender/animation.cpp | 16 +++------------- components/nifogre/ogrenifloader.cpp | 10 +++++++++- components/nifogre/skeleton.cpp | 11 +++++------ components/nifogre/skeleton.hpp | 3 +-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d51a30a770..31f54107eb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -97,9 +97,9 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); if(mSkelBase != objlist.mSkelBase) { - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < objlist.mControllers.size();i++) { NifOgre::NodeTargetValue *dstval; @@ -114,23 +114,13 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b } } - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); - boneiter = skel->getBoneIterator(); - while(boneiter.hasMoreElements()) + if(objlist.mTextKeys.size() > 0) { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty()) continue; - - objlist.mTextKeys[bone->getHandle()] = Ogre::any_cast(data); if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); } - - break; } } for(size_t i = 0;i < objlist.mControllers.size();i++) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 90147a43bc..97dfc59ef7 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -649,7 +649,14 @@ class NIFObjectLoader Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiStringExtraData) + if(e->recType == Nif::RC_NiTextKeyExtraData) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); + objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk); + } + else if(e->recType == Nif::RC_NiStringExtraData) { const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information @@ -661,6 +668,7 @@ class NIFObjectLoader flags |= 0x80000000; } } + e = e->extra; } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 3660be81bd..1809212a78 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -193,7 +193,6 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); animroot = bone; - bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(textkeys)); } e = e->extra; } @@ -287,16 +286,16 @@ Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, con { /* We need to be a little aggressive here, since some NIFs have a crap-ton * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: - * There are no bones used for skinning, there are no controllers on non- - * NiTriShape nodes, there are no nodes named "AttachLight", and the tree - * consists of NiNode, NiTriShape, and RootCollisionNode types only. + * There are no bones used for skinning, there are no controllers, there + * are no nodes named "AttachLight", and the tree consists of NiNode, + * NiTriShape, and RootCollisionNode types only. */ if(!node->boneTrafo) { - if(node->recType == Nif::RC_NiTriShape) - return Ogre::SkeletonPtr(); if(node->controller.empty() && node->name != "AttachLight") { + if(node->recType == Nif::RC_NiTriShape) + return Ogre::SkeletonPtr(); if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) { const Nif::NiNode *ninode = static_cast(node); diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp index c69c2a12fe..e71dcfb158 100644 --- a/components/nifogre/skeleton.hpp +++ b/components/nifogre/skeleton.hpp @@ -37,8 +37,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader } static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); - - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); // Lookup to retrieve an Ogre bone handle for a given Nif record index @@ -48,6 +46,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader static LoaderMap sLoaders; public: + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void loadResource(Ogre::Resource *resource); static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); From a7776e124cda07bc69bae504eebe6ccdb14bb07f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 00:22:31 -0700 Subject: [PATCH 1121/1483] Only set mNonAccumRoot from mSkelBase --- apps/openmw/mwrender/animation.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 31f54107eb..54416c45a8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,7 +98,15 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b boneiter.getNext()->setManuallyControlled(true); Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mSkelBase != objlist.mSkelBase) + if(mSkelBase == objlist.mSkelBase) + { + if(objlist.mTextKeys.size() > 0) + { + mAccumRoot = mInsert; + mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); + } + } + else { for(size_t i = 0;i < objlist.mControllers.size();i++) { @@ -113,15 +121,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b dstval->setNode(bone); } } - - if(objlist.mTextKeys.size() > 0) - { - if(!mNonAccumRoot) - { - mAccumRoot = mInsert; - mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); - } - } } for(size_t i = 0;i < objlist.mControllers.size();i++) { From a608e7ed06883ebc2b0ae09702bc133ffc2b1095 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 22 Apr 2013 09:56:11 +0200 Subject: [PATCH 1122/1483] updated changelog once more --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index d5a5dcc183..c033f95475 100644 --- a/readme.txt +++ b/readme.txt @@ -137,6 +137,8 @@ Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon Bug #725: Auto calculate stats +Bug #728: Failure to open container and talk dialogue +Bug #731: Crash with Mush-Mere's "background" topic Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From 9485a4aa6df48e9370b87a9bee5aec812cdca003 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 01:40:41 -0700 Subject: [PATCH 1123/1483] Look through the whole animation stack to find the "velocity" --- apps/openmw/mwrender/animation.cpp | 55 +++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 +-- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 54416c45a8..d71b33cddf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -209,26 +209,26 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -void Animation::calcAnimVelocity() +float Animation::calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, const std::string &groupname, const NifOgre::TextKeyMap *keys) { const Ogre::NodeAnimationTrack *track = 0; - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); while(!track && trackiter.hasMoreElements()) { const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + if(cur->getAssociatedNode()->getName() == bonename) track = cur; } if(track && track->getNumKeyFrames() > 1) { - const std::string loopstart = mCurrentGroup+": loop start"; - const std::string loopstop = mCurrentGroup+": loop stop"; + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; float loopstarttime = 0.0f; - float loopstoptime = mCurrentAnim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); - while(keyiter != mCurrentKeys->end()) + float loopstoptime = anim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); + while(keyiter != keys->end()) { if(keyiter->second == loopstart) loopstarttime = keyiter->first; @@ -245,13 +245,15 @@ void Animation::calcAnimVelocity() Ogre::TransformKeyFrame startkf(0, loopstarttime); Ogre::TransformKeyFrame endkf(0, loopstoptime); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstoptime), &endkf); - mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); + return startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); } } + + return 0.0f; } static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) @@ -423,27 +425,34 @@ bool Animation::handleEvent(float time, const std::string &evt) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { - bool found = false; + bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); - mCurrentAnim = skel->getAnimation(groupname); - mCurrentKeys = &iter->mTextKeys.begin()->second; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; + Ogre::Animation *anim = skel->getAnimation(groupname); + const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; + if(!foundanim) + { + mCurrentAnim = anim; + mCurrentKeys = keys; + mCurrentGroup = groupname; + mCurrentControllers = &iter->mControllers; - mAnimVelocity = 0.0f; - if(mNonAccumRoot) - calcAnimVelocity(); + mAnimVelocity = 0.0f; + foundanim = true; + } - found = true; - break; + if(!mNonAccumRoot) + break; + + mAnimVelocity = calcAnimVelocity(anim, mNonAccumRoot->getName(), groupname, keys); + if(mAnimVelocity > 0.0f) break; } } - if(!found) + if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b60bd21a85..cd2523b634 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -54,7 +54,7 @@ protected: std::string mCurrentGroup; std::vector > *mCurrentControllers; - NifOgre::TextKeyMap *mCurrentKeys; + const NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -65,7 +65,8 @@ protected: float mAnimVelocity; float mAnimSpeedMult; - void calcAnimVelocity(); + static float calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, + const std::string &groupname, const NifOgre::TextKeyMap *keys); /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ From d936291dbf2b7c9e5240aad64b1d338aed2207df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 02:53:32 -0700 Subject: [PATCH 1124/1483] Remove an unused ostream operator<< --- components/nifogre/ogrenifloader.cpp | 9 --------- components/nifogre/ogrenifloader.hpp | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 97dfc59ef7..dc6bb8d246 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -44,15 +44,6 @@ #include "material.hpp" #include "mesh.hpp" -namespace std -{ - -// TODO: Do something useful -ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) -{ return o; } - -} - namespace NifOgre { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 8e220ea38d..d0ff942177 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -98,14 +98,4 @@ typedef Ogre::SharedPtr > NodeTargetValueRealPtr; } -namespace std -{ - -// These operators allow extra data types to be stored in an Ogre::Any -// object, which can then be stored in user object bindings on the nodes - -ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&); - -} - #endif From 59137d93c99bdd9795a0dd0be7d3e9d4e63a2bb0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 03:24:02 -0700 Subject: [PATCH 1125/1483] Partially handle NiGeomMorpherController The morphs aren't actually applied yet, but the Ogre controller is set up so all that has to be done is to implement the setValue method. --- components/nifogre/mesh.cpp | 14 +++++++++ components/nifogre/ogrenifloader.cpp | 45 +++++++++++++++++++++++++++- components/nifogre/skeleton.cpp | 3 +- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c30..851160de2e 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -116,6 +116,20 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape std::vector srcNorms = data->normals; Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; bool vertShadowBuffer = false; + + if(!shape->controller.empty()) + { + Nif::ControllerPtr ctrl = shape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + break; + } + } while(!(ctrl=ctrl->next).empty()); + } + if(skin != NULL) { vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index dc6bb8d246..942b3858a7 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -293,7 +293,7 @@ public: } public: - Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data) + Value(const Ogre::MaterialPtr &material, const Nif::NiUVData *data) : mMaterial(material) , mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) @@ -363,6 +363,36 @@ public: typedef DefaultFunction Function; }; +class GeomMorpherController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::SubEntity *mSubEntity; + std::vector mMorphs; + + public: + Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data) + : mSubEntity(subent) + , mMorphs(data->mMorphs) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 0.0f; + } + + virtual void setValue(Ogre::Real value) + { + // TODO: Implement + } + }; + + typedef DefaultFunction Function; +}; + /** Object creator for NIFs. This is the main class responsible for creating * "live" Ogre objects (entities, particle systems, controllers, etc) from @@ -429,6 +459,19 @@ class NIFObjectLoader objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } + else if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); + + Ogre::SubEntity *subent = entity->getSubEntity(0); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(subent, geom->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } ctrl = ctrl->next; } } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 1809212a78..1306d037c2 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -179,7 +179,8 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, ctrls.push_back(static_cast(ctrl.getPtr())); else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController + ctrl->recType == Nif::RC_NiUVController || + ctrl->recType == Nif::RC_NiGeomMorpherController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; From adc6a948c7ed308c57c5996c57c8227c91d4af99 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 03:41:38 -0700 Subject: [PATCH 1126/1483] Add methods to get the rotation, translation, and scale from a NodeTargetValue --- components/nifogre/ogrenifloader.cpp | 41 ++++++++++++++++++++-------- components/nifogre/ogrenifloader.hpp | 4 ++- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 942b3858a7..451993cf4c 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -135,11 +135,14 @@ public: , mData(data->mVis) { } - virtual void applyToNode(Ogre::Node *node, float time) const - { - bool vis = calculate(time); - setVisible(node, vis); - } + virtual Ogre::Quaternion getRotation(float time) const + { return Ogre::Quaternion(); } + + virtual Ogre::Vector3 getTranslation(float time) const + { return Ogre::Vector3(0.0f); } + + virtual Ogre::Vector3 getScale(float time) const + { return Ogre::Vector3(1.0f); } virtual Ogre::Real getValue() const { @@ -149,7 +152,8 @@ public: virtual void setValue(Ogre::Real time) { - Value::applyToNode(mNode, time); + bool vis = calculate(time); + setVisible(mNode, vis); } }; @@ -223,7 +227,7 @@ public: float a = (time-last->mTime) / (iter->mTime-last->mTime); return Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue); } - return Ogre::Quaternion(); + return keys.back().mValue; } public: @@ -234,14 +238,25 @@ public: , mScales(data->mScales) { } - virtual void applyToNode(Ogre::Node *node, float time) const + virtual Ogre::Quaternion getRotation(float time) const { if(mRotations.mKeys.size() > 0) - node->setOrientation(interpKey(mRotations.mKeys, time)); + return interpKey(mRotations.mKeys, time); + return Ogre::Quaternion(); + } + + virtual Ogre::Vector3 getTranslation(float time) const + { if(mTranslations.mKeys.size() > 0) - node->setPosition(interpKey(mTranslations.mKeys, time)); + return interpKey(mTranslations.mKeys, time); + return Ogre::Vector3(0.0f); + } + + virtual Ogre::Vector3 getScale(float time) const + { if(mScales.mKeys.size() > 0) - node->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); + return Ogre::Vector3(interpKey(mScales.mKeys, time)); + return Ogre::Vector3(1.0f); } virtual Ogre::Real getValue() const @@ -252,7 +267,9 @@ public: virtual void setValue(Ogre::Real time) { - Value::applyToNode(mNode, time); + mNode->setOrientation(Value::getRotation(time)); + mNode->setPosition(Value::getTranslation(time)); + mNode->setScale(Value::getScale(time)); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index d0ff942177..40577e4515 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -87,7 +87,9 @@ public: NodeTargetValue(Ogre::Node *target) : mNode(target) { } - virtual void applyToNode(Ogre::Node *node, float time) const = 0; + virtual Ogre::Quaternion getRotation(T value) const = 0; + virtual Ogre::Vector3 getTranslation(T value) const = 0; + virtual Ogre::Vector3 getScale(T value) const = 0; void setNode(Ogre::Node *target) { mNode = target; } From cc70c6263bf377f600d8af023985ec8a092c3f5a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 04:10:46 -0700 Subject: [PATCH 1127/1483] Use the NodeTargetValue for the NonAccum root --- apps/openmw/mwrender/animation.cpp | 114 ++++++++++------------------- apps/openmw/mwrender/animation.hpp | 4 +- 2 files changed, 42 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d71b33cddf..5700af3d6c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -41,12 +41,12 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentAnim(NULL) , mCurrentControllers(NULL) , mCurrentKeys(NULL) , mCurrentTime(0.0f) , mPlaying(false) , mLooping(false) + , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { @@ -209,48 +209,31 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, const std::string &groupname, const NifOgre::TextKeyMap *keys) +float Animation::calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys) { - const Ogre::NodeAnimationTrack *track = 0; - - Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; + float loopstarttime = 0.0f; + float loopstoptime = std::numeric_limits::max(); + NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); + while(keyiter != keys->end()) { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == bonename) - track = cur; + if(keyiter->second == loopstart) + loopstarttime = keyiter->first; + else if(keyiter->second == loopstop) + { + loopstoptime = keyiter->first; + break; + } + keyiter++; } - if(track && track->getNumKeyFrames() > 1) + if(loopstoptime > loopstarttime) { - const std::string loopstart = groupname+": loop start"; - const std::string loopstop = groupname+": loop stop"; - float loopstarttime = 0.0f; - float loopstoptime = anim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); - while(keyiter != keys->end()) - { - if(keyiter->second == loopstart) - loopstarttime = keyiter->first; - else if(keyiter->second == loopstop) - { - loopstoptime = keyiter->first; - break; - } - keyiter++; - } + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(loopstarttime); + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(loopstarttime); - if(loopstoptime > loopstarttime) - { - Ogre::TransformKeyFrame startkf(0, loopstarttime); - Ogre::TransformKeyFrame endkf(0, loopstoptime); - - track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstoptime), &endkf); - - return startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); - } + return startpos.distance(endpos) / (loopstoptime-loopstarttime); } return 0.0f; @@ -298,20 +281,8 @@ Ogre::Vector3 Animation::updatePosition() { Ogre::Vector3 posdiff; - Ogre::TransformKeyFrame kf(0, mCurrentTime); - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *track = trackiter.getNext(); - if(track->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - { - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); - break; - } - } - /* Get the non-accumulation root's difference from the last update. */ - posdiff = (kf.getTranslate() - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -344,24 +315,9 @@ void Animation::reset(const std::string &start, const std::string &stop) mStopKey--; } - if(mNonAccumRoot) - { - const Ogre::NodeAnimationTrack *track = 0; - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - track = cur; - } - - if(track) - { - Ogre::TransformKeyFrame kf(0, mCurrentTime); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); - mLastPosition = kf.getTranslate() * mAccumulate; - } - } + if(mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * + mAccumulate; } @@ -431,24 +387,34 @@ void Animation::play(const std::string &groupname, const std::string &start, con { if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); - Ogre::Animation *anim = skel->getAnimation(groupname); const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + for(size_t i = 0;i < iter->mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + if(!foundanim) { - mCurrentAnim = anim; mCurrentKeys = keys; mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; - + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; + foundanim = true; } if(!mNonAccumRoot) break; - mAnimVelocity = calcAnimVelocity(anim, mNonAccumRoot->getName(), groupname, keys); + mAnimVelocity = calcAnimVelocity(nonaccumctrl, groupname, keys); if(mAnimVelocity > 0.0f) break; } } @@ -469,7 +435,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) Ogre::Vector3 movement(0.0f); timepassed *= mAnimSpeedMult; - while(mCurrentAnim && mPlaying) + while(!mCurrentGroup.empty() && mPlaying) { float targetTime = mCurrentTime + timepassed; if(mNextKey->first > targetTime) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cd2523b634..92f636d0ac 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -50,7 +50,6 @@ protected: Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - Ogre::Animation *mCurrentAnim; std::string mCurrentGroup; std::vector > *mCurrentControllers; @@ -62,10 +61,11 @@ protected: bool mPlaying; bool mLooping; + NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; - static float calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, + static float calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys); /* Updates a skeleton instance so that all bones matching the source skeleton (based on From bb64efc18e9252292b82f3540e487bb14b22901e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 05:08:52 -0700 Subject: [PATCH 1128/1483] Improve looping behavior --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 78 ++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 +- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 16d8115284..4684ca6ea7 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5700af3d6c..d065195ad5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -293,36 +293,51 @@ Ogre::Vector3 Animation::updatePosition() void Animation::reset(const std::string &start, const std::string &stop) { + std::string tag = mCurrentGroup+": "+start; mStartKey = mCurrentKeys->begin(); - - while(mStartKey != mCurrentKeys->end() && mStartKey->second != start) + while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) mStartKey++; - if(mStartKey != mCurrentKeys->end()) - mCurrentTime = mStartKey->first; - else + if(mStartKey == mCurrentKeys->end() && tag == "loop start") { + tag = mCurrentGroup+": start"; mStartKey = mCurrentKeys->begin(); - mCurrentTime = mStartKey->first; + while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) + mStartKey++; } - mNextKey = mStartKey; + if(mStartKey == mCurrentKeys->end()) + mStartKey = mCurrentKeys->begin(); - if(stop.length() > 0) - { - mStopKey = mStartKey; - while(mStopKey != mCurrentKeys->end() && mStopKey->second != stop) - mStopKey++; - if(mStopKey == mCurrentKeys->end()) - mStopKey--; - } + tag = mCurrentGroup+": "+stop; + mStopKey = mStartKey; + while(mStopKey != mCurrentKeys->end() && mStopKey->second != tag) + mStopKey++; + if(mStopKey == mCurrentKeys->end()) + mStopKey--; + + mCurrentTime = mStartKey->first; + mLoopStartKey = mStartKey; + mNextKey = mStartKey; + ++mNextKey; if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * - mAccumulate; + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; +} + +void Animation::doLoop() +{ + mCurrentTime = mLoopStartKey->first; + mNextKey = mLoopStartKey; + ++mNextKey; + if(mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; } -bool Animation::handleEvent(float time, const std::string &evt) +bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) { + float time = key->first; + const std::string &evt = key->second; + if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -347,25 +362,15 @@ bool Animation::handleEvent(float time, const std::string &evt) if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - /* Do nothing */ + mLoopStartKey = key; return true; } - if(evt.compare(off, len, "loop stop") == 0) + if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { if(mLooping) { - reset(mCurrentGroup+": loop start"); - if(mCurrentTime >= time) - return false; - return true; - } - } - else if(evt.compare(off, len, "stop") == 0) - { - if(mLooping) - { - reset(mCurrentGroup+": loop start"); + doLoop(); if(mCurrentTime >= time) return false; return true; @@ -421,7 +426,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); - reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); + reset(start, stop); setLooping(loop); mPlaying = true; } @@ -446,18 +451,15 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) break; } - float time = mNextKey->first; - const std::string &evt = mNextKey->second; - mNextKey++; - - mCurrentTime = time; + NifOgre::TextKeyMap::const_iterator key(mNextKey++); + mCurrentTime = key->first; if(mNonAccumRoot) movement += updatePosition(); mPlaying = (mLooping || mStopKey->first > mCurrentTime); timepassed = targetTime - mCurrentTime; - if(!handleEvent(time, evt)) + if(!handleTextKey(key)) break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 92f636d0ac..0d81cf3b4e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,6 +55,7 @@ protected: std::vector > *mCurrentControllers; const NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; float mCurrentTime; @@ -82,7 +83,9 @@ protected: */ void reset(const std::string &start, const std::string &stop=std::string()); - bool handleEvent(float time, const std::string &evt); + void doLoop(); + + bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); From a2fc43c7df22786b4d022be550928c2478a16c24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 20:41:54 -0700 Subject: [PATCH 1129/1483] Use reset to check that the animation exists and has the right markers --- apps/openmw/mwrender/animation.cpp | 123 ++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 10 ++- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d065195ad5..a17d225e96 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -209,14 +209,14 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys) +float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) { const std::string loopstart = groupname+": loop start"; const std::string loopstop = groupname+": loop stop"; float loopstarttime = 0.0f; - float loopstoptime = std::numeric_limits::max(); - NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); - while(keyiter != keys->end()) + float loopstoptime = 0.0f; + NifOgre::TextKeyMap::const_iterator keyiter = keys.begin(); + while(keyiter != keys.end()) { if(keyiter->second == loopstart) loopstarttime = keyiter->first; @@ -291,36 +291,44 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -void Animation::reset(const std::string &start, const std::string &stop) +bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { - std::string tag = mCurrentGroup+": "+start; - mStartKey = mCurrentKeys->begin(); - while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) - mStartKey++; - if(mStartKey == mCurrentKeys->end() && tag == "loop start") + std::string tag = groupname+": "+start; + NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); + while(startkey != keys.end() && startkey->second != tag) + startkey++; + if(startkey == keys.end() && tag == "loop start") { - tag = mCurrentGroup+": start"; - mStartKey = mCurrentKeys->begin(); - while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) - mStartKey++; + tag = groupname+": start"; + startkey = keys.begin(); + while(startkey != keys.end() && startkey->second != tag) + startkey++; } - if(mStartKey == mCurrentKeys->end()) - mStartKey = mCurrentKeys->begin(); + if(startkey == keys.end()) + return false; - tag = mCurrentGroup+": "+stop; - mStopKey = mStartKey; - while(mStopKey != mCurrentKeys->end() && mStopKey->second != tag) - mStopKey++; - if(mStopKey == mCurrentKeys->end()) - mStopKey--; + tag = groupname+": "+stop; + NifOgre::TextKeyMap::const_iterator stopkey(startkey); + while(stopkey != keys.end() && stopkey->second != tag) + stopkey++; + if(stopkey == keys.end()) + return false; - mCurrentTime = mStartKey->first; + if(startkey == stopkey) + return false; + + mStartKey = startkey; mLoopStartKey = mStartKey; + mStopKey = stopkey; mNextKey = mStartKey; ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mCurrentTime = mStartKey->first; + + if(nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + + return true; } void Animation::doLoop() @@ -390,45 +398,46 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + for(size_t i = 0;i < iter->mControllers.size();i++) { - const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - - if(!foundanim) - { - mCurrentKeys = keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - - foundanim = true; - } - - if(!mNonAccumRoot) + nonaccumctrl = dstval; break; - - mAnimVelocity = calcAnimVelocity(nonaccumctrl, groupname, keys); - if(mAnimVelocity > 0.0f) break; + } } + + if(!foundanim) + { + if(!reset(keys, nonaccumctrl, groupname, start, stop)) + continue; + mCurrentKeys = &keys; + mCurrentGroup = groupname; + mCurrentControllers = &iter->mControllers; + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + + setLooping(loop); + mPlaying = true; + + foundanim = true; + } + + if(!mNonAccumRoot) + break; + + mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); + if(mAnimVelocity > 0.0f) break; } if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); - - reset(start, stop); - setLooping(loop); - mPlaying = true; } catch(std::exception &e) { std::cerr<< e.what() < *nonaccumctrl, - const std::string &groupname, const NifOgre::TextKeyMap *keys); + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, + NifOgre::NodeTargetValue *nonaccumctrl, + const std::string &groupname); /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ @@ -79,9 +80,10 @@ protected: /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If - * the marker is not found, it resets to the beginning or end respectively. + * the marker is not found, or if the markers are the same, it returns + * false. */ - void reset(const std::string &start, const std::string &stop=std::string()); + bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); void doLoop(); From 7279e015e9e76a0dec940f2f10fd2948c39500f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 20:59:55 -0700 Subject: [PATCH 1130/1483] Search the textkeys to check if an animation group exists --- apps/openmw/mwrender/animation.cpp | 19 ++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a17d225e96..b5f23b2c4e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,11 +169,28 @@ Ogre::Node *Animation::getNode(const std::string &name) } +NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) +{ + NifOgre::TextKeyMap::const_iterator iter(keys.begin()); + for(;iter != keys.end();iter++) + { + if(iter->second.compare(0, groupname.size(), groupname) == 0 && + iter->second.compare(groupname.size(), 2, ": ") == 0) + break; + } + return iter; +} + + bool Animation::hasAnimation(const std::string &anim) { for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(anim)) + if(iter->mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + if(findGroupStart(keys, anim) != keys.end()) return true; } return false; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 06c2b485b9..6393ee7c91 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -78,6 +78,8 @@ protected: * returns the wanted movement vector from the previous update. */ Ogre::Vector3 updatePosition(); + static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); + /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If * the marker is not found, or if the markers are the same, it returns From c3ce49798a315c9fd8065b356f7fae87557c69cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 21:34:39 -0700 Subject: [PATCH 1131/1483] Fix animation velocity calculation --- apps/openmw/mwrender/animation.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b5f23b2c4e..45f2a6fcb4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -228,29 +228,31 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) { + const std::string start = groupname+": start"; const std::string loopstart = groupname+": loop start"; const std::string loopstop = groupname+": loop stop"; - float loopstarttime = 0.0f; - float loopstoptime = 0.0f; - NifOgre::TextKeyMap::const_iterator keyiter = keys.begin(); + const std::string stop = groupname+": stop"; + float starttime = std::numeric_limits::max(); + float stoptime = 0.0f; + NifOgre::TextKeyMap::const_iterator keyiter(keys.begin()); while(keyiter != keys.end()) { - if(keyiter->second == loopstart) - loopstarttime = keyiter->first; - else if(keyiter->second == loopstop) + if(keyiter->second == start || keyiter->second == loopstart) + starttime = keyiter->first; + else if(keyiter->second == loopstop || keyiter->second == stop) { - loopstoptime = keyiter->first; + stoptime = keyiter->first; break; } keyiter++; } - if(loopstoptime > loopstarttime) + if(stoptime > starttime) { - Ogre::Vector3 startpos = nonaccumctrl->getTranslation(loopstarttime); - Ogre::Vector3 endpos = nonaccumctrl->getTranslation(loopstarttime); + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime); + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime); - return startpos.distance(endpos) / (loopstoptime-loopstarttime); + return startpos.distance(endpos) / (stoptime-starttime); } return 0.0f; From 8782ae6976aa316a5394dd4e33c6cf0cd290779a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 23:35:50 -0700 Subject: [PATCH 1132/1483] Separate some Animation fields into a separate AnimLayer class --- apps/openmw/mwmechanics/character.cpp | 4 - apps/openmw/mwrender/animation.cpp | 179 +++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 52 ++++---- 3 files changed, 130 insertions(+), 105 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4684ca6ea7..07f7b69401 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -304,11 +304,7 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) - { - if(mAnimation) - mAnimation->setLooping(loop); return; - } mState = state; if(!mAnimation) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 45f2a6fcb4..4c5a869856 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,6 +18,32 @@ namespace MWRender { +Animation::AnimLayer::AnimLayer() + : mControllers(NULL) + , mTextKeys(NULL) + , mTime(0.0f) + , mPlaying(false) + , mLooping(false) +{ +} + + +Ogre::Real Animation::AnimationValue::getValue() const +{ + size_t idx = mIndex; + while(idx > 0 && mAnimation->mLayer[idx].mGroupName.empty()) + idx--; + if(!mAnimation->mLayer[idx].mGroupName.empty()) + return mAnimation->mLayer[idx].mTime; + return 0.0f; +} + +void Animation::AnimationValue::setValue(Ogre::Real value) +{ + mAnimation->mLayer[mIndex].mTime = value; +} + + void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) { for(size_t i = 0;i < objects.mParticles.size();i++) @@ -32,7 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) , mPtr(ptr) , mController(NULL) , mInsert(NULL) @@ -41,11 +67,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentControllers(NULL) - , mCurrentKeys(NULL) - , mCurrentTime(0.0f) - , mPlaying(false) - , mLooping(false) , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) @@ -127,9 +148,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } - - if(!mCurrentControllers || (*mCurrentControllers).size() == 0) - mCurrentControllers = &objlist.mControllers; } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -215,10 +233,6 @@ void Animation::setSpeed(float speed) mAnimSpeedMult = speed / mAnimVelocity; } -void Animation::setLooping(bool loop) -{ - mLooping = loop; -} void Animation::updatePtr(const MWWorld::Ptr &ptr) { @@ -301,7 +315,7 @@ Ogre::Vector3 Animation::updatePosition() Ogre::Vector3 posdiff; /* Get the non-accumulation root's difference from the last update. */ - posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -310,7 +324,7 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -336,31 +350,31 @@ bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue< if(startkey == stopkey) return false; - mStartKey = startkey; - mLoopStartKey = mStartKey; - mStopKey = stopkey; - mNextKey = mStartKey; - ++mNextKey; + mLayer[layeridx].mStartKey = startkey; + mLayer[layeridx].mLoopStartKey = startkey; + mLayer[layeridx].mStopKey = stopkey; + mLayer[layeridx].mNextKey = startkey; + mLayer[layeridx].mNextKey++; - mCurrentTime = mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; - if(nonaccumctrl) - mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + if(layeridx == 0 && nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; return true; } -void Animation::doLoop() +void Animation::doLoop(size_t layeridx) { - mCurrentTime = mLoopStartKey->first; - mNextKey = mLoopStartKey; - ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; + mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; + mLayer[layeridx].mNextKey++; + if(layeridx == 0 && mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } -bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) +bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key) { float time = key->first; const std::string &evt = key->second; @@ -378,27 +392,27 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) return true; } - if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || - evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + if(evt.compare(0, mLayer[layeridx].mGroupName.size(), mLayer[layeridx].mGroupName) != 0 || + evt.compare(mLayer[layeridx].mGroupName.size(), 2, ": ") != 0) { - // Not ours + // Not ours, skip it return true; } - size_t off = mCurrentGroup.size()+2; + size_t off = mLayer[layeridx].mGroupName.size()+2; size_t len = evt.size() - off; if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - mLoopStartKey = key; + mLayer[layeridx].mLoopStartKey = key; return true; } if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLooping) + if(mLayer[layeridx].mLooping) { - doLoop(); - if(mCurrentTime >= time) + doLoop(layeridx); + if(mLayer[layeridx].mTime >= time) return false; return true; } @@ -412,6 +426,9 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { + // TODO: parameterize this + size_t layeridx = 0; + try { bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ @@ -422,34 +439,40 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + if(layeridx == 0) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) + for(size_t i = 0;i < iter->mControllers.size();i++) { - nonaccumctrl = dstval; - break; + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } } } if(!foundanim) { - if(!reset(keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) continue; - mCurrentKeys = &keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; - setLooping(loop); - mPlaying = true; + if(layeridx == 0) + { + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + } foundanim = true; } - if(!mNonAccumRoot) + if(!nonaccumctrl) break; mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); @@ -463,37 +486,43 @@ void Animation::play(const std::string &groupname, const std::string &start, con } } -Ogre::Vector3 Animation::runAnimation(float timepassed) +Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - timepassed *= mAnimSpeedMult; - while(!mCurrentGroup.empty() && mPlaying) + duration *= mAnimSpeedMult; + for(size_t layeridx = 0;layeridx < sMaxLayers;layeridx++) { - float targetTime = mCurrentTime + timepassed; - if(mNextKey->first > targetTime) + if(mLayer[layeridx].mGroupName.empty()) + continue; + + float timepassed = duration; + while(mLayer[layeridx].mPlaying) { - mCurrentTime = targetTime; - if(mNonAccumRoot) + float targetTime = mLayer[layeridx].mTime + timepassed; + if(mLayer[layeridx].mNextKey->first > targetTime) + { + mLayer[layeridx].mTime = targetTime; + if(layeridx == 0 && mNonAccumRoot) + movement += updatePosition(); + break; + } + + NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); + mLayer[layeridx].mTime = key->first; + if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - break; + + mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + timepassed = targetTime - mLayer[layeridx].mTime; + + if(!handleTextKey(layeridx, key)) + break; } - - NifOgre::TextKeyMap::const_iterator key(mNextKey++); - mCurrentTime = key->first; - if(mNonAccumRoot) - movement += updatePosition(); - - mPlaying = (mLooping || mStopKey->first > mCurrentTime); - timepassed = targetTime - mCurrentTime; - - if(!handleTextKey(key)) - break; + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); } - for(size_t i = 0;i < (*mCurrentControllers).size();i++) - (*mCurrentControllers)[i].update(); - if(mSkelBase) { const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6393ee7c91..96138cf749 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -23,20 +23,15 @@ protected: { private: Animation *mAnimation; + size_t mIndex; public: - AnimationValue(Animation *anim) : mAnimation(anim) + AnimationValue(Animation *anim, size_t layeridx) + : mAnimation(anim), mIndex(layeridx) { } - virtual Ogre::Real getValue() const - { - return mAnimation->mCurrentTime; - } - - virtual void setValue(Ogre::Real value) - { - mAnimation->mCurrentTime = value; - } + virtual Ogre::Real getValue() const; + virtual void setValue(Ogre::Real value); }; Ogre::SharedPtr > mAnimationBaseValuePtr; @@ -51,21 +46,28 @@ protected: Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::string mCurrentGroup; - std::vector > *mCurrentControllers; - const NifOgre::TextKeyMap *mCurrentKeys; - NifOgre::TextKeyMap::const_iterator mStartKey; - NifOgre::TextKeyMap::const_iterator mLoopStartKey; - NifOgre::TextKeyMap::const_iterator mStopKey; - NifOgre::TextKeyMap::const_iterator mNextKey; - float mCurrentTime; - bool mPlaying; - bool mLooping; - NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + static const size_t sMaxLayers = 1; + struct AnimLayer { + std::string mGroupName; + std::vector > *mControllers; + const NifOgre::TextKeyMap *mTextKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; + NifOgre::TextKeyMap::const_iterator mNextKey; + + float mTime; + + bool mPlaying; + bool mLooping; + + AnimLayer(); + } mLayer[sMaxLayers]; + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname); @@ -85,11 +87,11 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(); + void doLoop(size_t layeridx); - bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); + bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); @@ -113,8 +115,6 @@ public: void setSpeed(float speed); - void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); From e3781769371e8c736bcf2643537c60cf6fe106f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 00:15:31 -0700 Subject: [PATCH 1133/1483] Don't update controllers that have already been updated --- apps/openmw/mwrender/animation.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4c5a869856..0166eb8436 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -519,8 +519,23 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(!handleTextKey(layeridx, key)) break; } - for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) - (*(mLayer[layeridx].mControllers))[i].update(); + + bool updatectrls = true; + for(size_t i = layeridx-1;i < layeridx;i--) + { + if(mLayer[i].mGroupName.empty()) + continue; + if(mLayer[i].mControllers == mLayer[layeridx].mControllers) + { + updatectrls = false; + break; + } + } + if(updatectrls) + { + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); + } } if(mSkelBase) From afe7b3c64c4adafd112b4d151d8866ffefb4a725 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 10:56:55 +0200 Subject: [PATCH 1134/1483] added additional type argument to IdCollection::appendBlankRecord --- apps/opencs/model/world/idcollection.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 7052b300e4..45b4961aab 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -16,6 +16,7 @@ #include #include "columnbase.hpp" +#include "universalid.hpp" namespace CSMWorld { @@ -53,7 +54,9 @@ namespace CSMWorld virtual void removeRows (int index, int count) = 0; - virtual void appendBlankRecord (const std::string& id) = 0; + virtual void appendBlankRecord (const std::string& id, + UniversalId::Type type = UniversalId::Type_None) = 0; + ///< \param type Will be ignored, unless the collection supports multiple record types virtual int searchId (const std::string& id) const = 0; ////< Search record with \a id. @@ -143,7 +146,9 @@ namespace CSMWorld virtual void removeRows (int index, int count) ; - virtual void appendBlankRecord (const std::string& id); + virtual void appendBlankRecord (const std::string& id, + UniversalId::Type type = UniversalId::Type_None); + ///< \param type Will be ignored, unless the collection supports multiple record types virtual int searchId (const std::string& id) const; ////< Search record with \a id. @@ -300,7 +305,8 @@ namespace CSMWorld } template - void IdCollection::appendBlankRecord (const std::string& id) + void IdCollection::appendBlankRecord (const std::string& id, + UniversalId::Type type) { ESXRecordT record; IdAccessorT().getId (record) = id; From 808718d96708d9833e7a8fe959de1e8823802039 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 11:21:21 +0200 Subject: [PATCH 1135/1483] added referenceable record types to UniversalId --- apps/opencs/model/world/universalid.cpp | 26 +++++++++++++++++++++++++ apps/opencs/model/world/universalid.hpp | 25 +++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index c0241bc383..bd1632e3e7 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -29,6 +29,8 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, + "Referenceables" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -47,6 +49,30 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Activator, "Activator" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Potion, "Potion" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Apparatus, "Apparatus" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Armor, "Armor" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Book, "Book" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Clothing, "Clothing" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Container, "Container" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Creature, "Creature" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Door, "Door" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Ingredient, "Ingredient" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_CreatureLevelledList, + "Creature Levelled List" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_ItemLevelledList, + "Item Levelled List" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Light, "Light" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Lockpick, "Lockpick" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Miscellaneous, + "Miscellaneous" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Npc, "NPC" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Probe, "Probe" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Repair, "Repair" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Static, "Static" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Weapon, "Weapon" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 9b52aded1f..2c4b14eaf5 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -57,7 +57,30 @@ namespace CSMWorld Type_Spells, Type_Spell, Type_Cells, - Type_Cell + Type_Cell, + Type_Referenceables, + Type_Referenceable, + Type_Activator, + Type_Potion, + Type_Apparatus, + Type_Armor, + Type_Book, + Type_Clothing, + Type_Container, + Type_Creature, + Type_Door, + Type_Ingredient, + Type_CreatureLevelledList, + Type_ItemLevelledList, + Type_Light, + Type_Lockpick, + Type_Miscellaneous, + Type_Npc, + Type_Probe, + Type_Repair, + Type_Static, + Type_Weapon + }; private: From a17d17c19105557c88ff2cdcaca19df103f6fba6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 11:22:07 +0200 Subject: [PATCH 1136/1483] added additional type argument to IdCollection::load --- apps/opencs/model/world/idcollection.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 45b4961aab..7761929f3f 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -79,7 +79,9 @@ namespace CSMWorld virtual const RecordBase& getRecord (int index) const = 0; - virtual void load (ESM::ESMReader& reader, bool base) = 0; + virtual void load (ESM::ESMReader& reader, bool base, + UniversalId::Type type = UniversalId::Type_None) = 0; + ///< \param type Will be ignored, unless the collection supports multiple record types }; ///< \brief Access to ID field in records @@ -171,7 +173,9 @@ namespace CSMWorld virtual const Record& getRecord (int index) const; - virtual void load (ESM::ESMReader& reader, bool base); + virtual void load (ESM::ESMReader& reader, bool base, + UniversalId::Type type = UniversalId::Type_None); + ///< \param type Will be ignored, unless the collection supports multiple record types void addColumn (Column *column); }; @@ -348,7 +352,8 @@ namespace CSMWorld } template - void IdCollection::load (ESM::ESMReader& reader, bool base) + void IdCollection::load (ESM::ESMReader& reader, bool base, + UniversalId::Type type) { std::string id = reader.getHNOString ("NAME"); From e4c5aac9664db105fde2b31b0973d5c7b483d80a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 02:48:11 -0700 Subject: [PATCH 1137/1483] Keep track of the animation layers a given object list is animating on This only tracks layers they explicitly animate on. They may animate on other layers as well, if nothing else is animating on them. --- apps/openmw/mwrender/activatoranimation.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 63 +++++++++++++++------ apps/openmw/mwrender/animation.hpp | 11 +++- apps/openmw/mwrender/creatureanimation.cpp | 2 +- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index c3a3045c20..4eb844607c 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -22,7 +22,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) const std::string name = "meshes\\"+ref->mBase->mModel; addObjectList(mPtr.getRefData().getBaseNode(), name, false); - setRenderProperties(mObjectLists.back(), RV_Misc, RQG_Main, RQG_Alpha); + setRenderProperties(mObjects.back().mObjectList, RV_Misc, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0166eb8436..98e2f91043 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,9 +78,9 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mObjectLists.size();i++) - destroyObjectList(sceneMgr, mObjectLists[i]); - mObjectLists.clear(); + for(size_t i = 0;i < mObjects.size();i++) + destroyObjectList(sceneMgr, mObjects[i].mObjectList); + mObjects.clear(); } } @@ -93,9 +93,13 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b assert(mInsert); } - mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : - NifOgre::Loader::createObjectBase(mInsert, model)); - NifOgre::ObjectList &objlist = mObjectLists.back(); + mObjects.push_back(ObjectInfo()); + ObjectInfo &obj = mObjects.back(); + obj.mActiveLayers = 0; + obj.mObjectList = (!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + + NifOgre::ObjectList &objlist = obj.mObjectList; if(objlist.mSkelBase) { if(!mSkelBase) @@ -202,12 +206,12 @@ NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::Tex bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) + for(std::vector::const_iterator iter(mObjects.begin());iter != mObjects.end();iter++) { - if(iter->mTextKeys.size() == 0) + if(iter->mObjectList.mTextKeys.size() == 0) continue; - const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + const NifOgre::TextKeyMap &keys = iter->mObjectList.mTextKeys.begin()->second; if(findGroupStart(keys, anim) != keys.end()) return true; } @@ -430,21 +434,45 @@ void Animation::play(const std::string &groupname, const std::string &start, con size_t layeridx = 0; try { + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) + for(std::vector::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) { - if(iter->mTextKeys.size() == 0) + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) continue; - const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; if(layeridx == 0) { - for(size_t i = 0;i < iter->mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); if(dstval && dstval->getNode() == mNonAccumRoot) { nonaccumctrl = dstval; @@ -459,7 +487,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con continue; mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mControllers = &objlist.mControllers; mLayer[layeridx].mLooping = loop; mLayer[layeridx].mPlaying = true; @@ -469,6 +497,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mAnimVelocity = 0.0f; } + iter->mActiveLayers |= (1<getSkeleton(); - for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) { - Ogre::Entity *ent = iter->mSkelBase; + Ogre::Entity *ent = iter->mObjectList.mSkelBase; if(!ent) continue; Ogre::SkeletonInstance *inst = ent->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 96138cf749..840c22ae47 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,9 +38,18 @@ protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; + struct ObjectInfo { + NifOgre::ObjectList mObjectList; + /* Bit-field specifying which animation layers this object list is + * explicitly animating on (1 = layer 0, 2 = layer 1, 4 = layer 2. + * etc). + */ + int mActiveLayers; + }; + Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; - std::vector mObjectLists; + std::vector mObjects; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 51632b2ee1..97c28c0ae4 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -25,7 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); addObjectList(mPtr.getRefData().getBaseNode(), model, false); - setRenderProperties(mObjectLists.back(), RV_Actors, RQG_Main, RQG_Alpha); + setRenderProperties(mObjects.back().mObjectList, RV_Actors, RQG_Main, RQG_Alpha); } } From cfccf0981dee740e725eb819d1dbb2cf00c66b2d Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 23 Apr 2013 13:24:06 +0400 Subject: [PATCH 1138/1483] update IndexedStore::setUp() for multiple datafile support --- apps/openmw/mwworld/store.hpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fb3f8c4826..959b944e10 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -872,7 +872,28 @@ namespace MWWorld } void setUp() { - std::sort(mStatic.begin(), mStatic.end(), Compare()); + /// \note This method sorts indexed values for further + /// searches. Every loaded item is present in storage, but + /// latest loaded shadows any previous while searching. + /// If memory cost will be too high, it is possible to remove + /// unused values. + + Compare cmp; + + std::stable_sort(mStatic.begin(), mStatic.end(), cmp); + + typename std::vector::iterator first, next; + next = first = mStatic.begin(); + + while (first != mStatic.end() && ++next != mStatic.end()) { + while (next != mStatic.end() && !cmp(*first, *next)) { + ++next; + } + if (first != --next) { + std::swap(*first, *next); + } + first = ++next; + } } const T *search(int index) const { From c4806f01f850bbf18052659e45b222553b9f747c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 03:42:00 -0700 Subject: [PATCH 1139/1483] Use a separate list of controllers to update This should make it easier to figure out what controllers need to be updated for various animation sources and layers. --- apps/openmw/mwrender/animation.cpp | 220 ++++++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 3 + 2 files changed, 139 insertions(+), 84 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 98e2f91043..fbf5725c46 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -71,6 +71,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + /* As long as we remain under 128 active controllers, we can avoid + * reallocations. */ + mActiveCtrls.reserve(128); } Animation::~Animation() @@ -179,6 +182,79 @@ void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::ui } +void Animation::updateActiveControllers() +{ + mActiveCtrls.clear(); + + /* First, get all controllers that don't target a node, or that target + * nodes that don't belong to any particular layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + std::vector >::const_iterator ctrl(obj->mObjectList.mControllers.begin()); + for(;ctrl != obj->mObjectList.mControllers.end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*if(getLayerByName(dstval->getNode()->getName()) >= 0)*/ + continue; + } + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + std::vector > *ctrls = NULL; + size_t layer = 0; + while(layer < sMaxLayers) + { + /* Now get controllers that target nodes that belong to this layer from + * whatever objectlist is active on this layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1<mObjectList.mControllers; + break; + } + } + + /* Check if any objectlists are active on subsequent layers. Include + * those layers if not. + */ + size_t nextlayer = layer+1; + for(;nextlayer < sMaxLayers;nextlayer++) + { + for(obj = mObjects.begin();obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1< >::const_iterator ctrl(ctrls->begin()); + for(;ctrl != ctrls->end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*ssize_t idx = getLayerByName(dstval->getNode()->getName()); + if(idx >= (ssize_t)layer && idx < (ssize_t)nextlayer)*/ + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + layer = nextlayer; + } +} + + Ogre::Node *Animation::getNode(const std::string &name) { if(mSkelBase) @@ -433,86 +509,76 @@ void Animation::play(const std::string &groupname, const std::string &start, con // TODO: parameterize this size_t layeridx = 0; - try { - for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) - iter->mActiveLayers &= ~(1<::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) + { + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + if(layeridx == 0) { - // Do not allow layer 0 to be disabled - assert(layeridx != 0); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + } - mLayer[layeridx].mGroupName.clear(); - mLayer[layeridx].mTextKeys = NULL; - mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; - mLayer[layeridx].mPlaying = false; + if(!foundanim) + { + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + continue; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &objlist.mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; if(layeridx == 0) { - mNonAccumCtrl = NULL; + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; } - return; + iter->mActiveLayers |= (1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) - { - NifOgre::ObjectList &objlist = iter->mObjectList; - if(objlist.mTextKeys.size() == 0) - continue; + if(!nonaccumctrl) + break; - const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) - { - for(size_t i = 0;i < objlist.mControllers.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - } - - if(!foundanim) - { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) - continue; - mLayer[layeridx].mGroupName = groupname; - mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; - mLayer[layeridx].mPlaying = true; - - if(layeridx == 0) - { - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - } - - iter->mActiveLayers |= (1< 0.0f) break; - } - if(!foundanim) - throw std::runtime_error("Failed to find animation "+groupname); - } - catch(std::exception &e) { - std::cerr<< e.what() < 0.0f) break; } + if(!foundanim) + std::cerr<< "Failed to find animation "<getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 840c22ae47..4860f44f5c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -58,6 +58,7 @@ protected: NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; struct AnimLayer { @@ -107,6 +108,8 @@ protected: static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + void updateActiveControllers(); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); From 8c9e2e0ee9e24b444efa67f811ed8be1cd87fbcb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 05:34:08 -0700 Subject: [PATCH 1140/1483] Improve handling of reaching the stop animation text key --- apps/openmw/mwrender/animation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fbf5725c46..d98a32828a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -449,6 +449,7 @@ void Animation::doLoop(size_t layeridx) mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; mLayer[layeridx].mNextKey++; + mLayer[layeridx].mPlaying = true; if(layeridx == 0 && mNonAccumCtrl) mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } @@ -608,7 +609,7 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); timepassed = targetTime - mLayer[layeridx].mTime; if(!handleTextKey(layeridx, key)) From 44ac0a7c1856bf463f18ed435d554574745d4c50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Apr 2013 22:47:21 +0200 Subject: [PATCH 1141/1483] Use one vertex buffer for all UV coordinates --- components/nifogre/mesh.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c30..6d940deed3 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -260,13 +260,24 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Texture UV coordinates size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) + if (numUVs) { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + + for(size_t i = 0; i < numUVs; i++) + decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + + vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + + std::vector allUVs; + allUVs.reserve(srcVerts.size()*numUVs); + for (size_t vert = 0; vertuvlist[i][vert]); + + vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); bind->setBinding(nextBuf++, vbuf); } From 634b0fd067a7c4ac65123be69dd29c0c4739be2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 17:57:40 -0700 Subject: [PATCH 1142/1483] Fix for controller delta time going below start time --- components/nifogre/ogrenifloader.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 451993cf4c..95ba439d1b 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -65,11 +65,7 @@ public: , mStopTime(ctrl->timeStop) { if(mDeltaInput) - { mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); - } } virtual Ogre::Real calculate(Ogre::Real value) @@ -77,6 +73,9 @@ public: if(mDeltaInput) { mDeltaCount += value*mFrequency; + if(mDeltaCount < mStartTime) + mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, + mStopTime - mStartTime); mDeltaCount = std::fmod(mDeltaCount - mStartTime, mStopTime - mStartTime) + mStartTime; return mDeltaCount; From 7e2995bc2f7b21f2335424e0d49e7d5231a673d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 19:43:26 -0700 Subject: [PATCH 1143/1483] Fix setting up active controllers --- apps/openmw/mwrender/animation.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d98a32828a..cb54a03665 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -155,6 +155,8 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } + + mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -231,7 +233,7 @@ void Animation::updateActiveControllers() { for(obj = mObjects.begin();obj != mObjects.end();obj++) { - if((obj->mActiveLayers&(1<mActiveLayers&(1< Date: Tue, 23 Apr 2013 20:42:54 -0700 Subject: [PATCH 1144/1483] Don't create Ogre animations for skeletons --- components/nifogre/ogrenifloader.cpp | 28 +++- components/nifogre/skeleton.cpp | 220 ++------------------------- components/nifogre/skeleton.hpp | 4 +- 3 files changed, 37 insertions(+), 215 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 95ba439d1b..e451326fee 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -676,6 +676,32 @@ class NIFObjectLoader } + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) + { + TextKeyMap textkeys; + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + return textkeys; + } + + static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags, int animflags, int partflags) @@ -704,7 +730,7 @@ class NIFObjectLoader const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk); + objectlist.mTextKeys[trgtid] = extractTextKeys(tk); } else if(e->recType == Nif::RC_NiStringExtraData) { diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 1306d037c2..3aec920fc4 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -11,142 +11,7 @@ namespace NifOgre { -void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) -{ - Ogre::Animation *anim = skel->createAnimation(name, stopTime); - - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *kfc = ctrls[i]; - if(kfc->data.empty()) - continue; - const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - - Ogre::Bone *bone = skel->getBone(targets[i]); - // NOTE: For some reason, Ogre doesn't like the node track ID being different from - // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? - anim->getNodeTrack(bone->getHandle()) : - anim->createNodeTrack(bone->getHandle(), bone); - - 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 = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - - bool didlast = false; - while(!didlast) - { - float curtime = std::numeric_limits::max(); - - //Get latest time - 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, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::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 - { - Nif::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 - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); -} - - -TextKeyMap NIFSkeletonLoader::extractTextKeys(const Nif::NiTextKeyExtraData *tk) -{ - TextKeyMap textkeys; - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - return textkeys; -} - -void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent) +void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent) { Ogre::Bone *bone; if(!skel->hasBone(node->name)) @@ -175,29 +40,16 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { - if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController || - ctrl->recType == Nif::RC_NiGeomMorpherController - )) + if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController || + ctrl->recType == Nif::RC_NiKeyframeController || + ctrl->recType == Nif::RC_NiGeomMorpherController + )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - textkeys = extractTextKeys(tk); - animroot = bone; - } - e = e->extra; - } - const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { @@ -205,7 +57,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); + buildBones(skel, children[i].getPtr(), bone); } } } @@ -218,68 +70,14 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); const Nif::Node *node = static_cast(nif->getRoot(0)); - std::vector ctrls; - Ogre::Bone *animroot = NULL; - TextKeyMap textkeys; try { - buildBones(skel, node, animroot, textkeys, ctrls); + buildBones(skel, node); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() < 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++) - { - const 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; - } - - std::string currentgroup; - TextKeyMap::const_iterator keyiter = textkeys.begin(); - for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) - { - std::string::size_type sep = keyiter->second.find(':'); - if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || - (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) - continue; - currentgroup = keyiter->second.substr(0, sep); - - if(skel->hasAnimation(currentgroup)) - continue; - - TextKeyMap::const_iterator lastkeyiter = textkeys.end(); - while((--lastkeyiter)->first > keyiter->first) - { - if(lastkeyiter->second.find(':') == currentgroup.length() && - lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) - break; - } - - buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - } } diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp index e71dcfb158..38cfe14e3d 100644 --- a/components/nifogre/skeleton.hpp +++ b/components/nifogre/skeleton.hpp @@ -36,8 +36,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader abort(); } - static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); + void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL); // Lookup to retrieve an Ogre bone handle for a given Nif record index std::map mNifToOgreHandleMap; @@ -46,7 +45,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader static LoaderMap sLoaders; public: - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void loadResource(Ogre::Resource *resource); static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); From 6f0b9a5f2cb98747715dbfa6c88b86f178c6f94c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 21:42:59 -0700 Subject: [PATCH 1145/1483] Avoid unnecessary multimap copies --- components/nifogre/ogrenifloader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e451326fee..57aa794038 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -676,9 +676,8 @@ class NIFObjectLoader } - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) + static void extractTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap &textkeys) { - TextKeyMap textkeys; for(size_t i = 0;i < tk->list.size();i++) { const std::string &str = tk->list[i].text; @@ -698,7 +697,6 @@ class NIFObjectLoader pos = nextpos; } } - return textkeys; } @@ -730,7 +728,7 @@ class NIFObjectLoader const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - objectlist.mTextKeys[trgtid] = extractTextKeys(tk); + extractTextKeys(tk, objectlist.mTextKeys[trgtid]); } else if(e->recType == Nif::RC_NiStringExtraData) { From 544011e0962b28b9cb978d90b9f1fe32455fb1ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 00:40:58 -0700 Subject: [PATCH 1146/1483] Fix 'start' text key fallback lookup --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cb54a03665..dc1312837a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -412,7 +412,7 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); while(startkey != keys.end() && startkey->second != tag) startkey++; - if(startkey == keys.end() && tag == "loop start") + if(startkey == keys.end() && start == "loop start") { tag = groupname+": start"; startkey = keys.begin(); From 26cc86ffdcd152b9acb6b953fff7de7acf2c48a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 00:42:45 -0700 Subject: [PATCH 1147/1483] Use the Nif node's transform for skinned fixups --- components/nifogre/mesh.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index 5637cd8285..ca92f62d49 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -109,7 +109,6 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const 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; @@ -139,10 +138,6 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // 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); - // 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. @@ -153,11 +148,10 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape const Nif::NodeList &bones = skin->bones; for(size_t b = 0;b < bones.length();b++) { - Ogre::Bone *bone = skel->getBone(bones[b]->name); Ogre::Matrix4 mat; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bone->_getFullTransform() * mat; + mat = bones[b]->getWorldTransform() * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) @@ -310,6 +304,8 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Assign bone weights for this TriShape if(skin != NULL) { + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(mName); + const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++) From 9e05ee53da793846d0ddebd0b960aba621a621a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 01:18:08 -0700 Subject: [PATCH 1148/1483] Avoid looking for the controller if there is no NonAccum node Also, make sure there is a controller before updating the position. --- apps/openmw/mwrender/animation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index dc1312837a..a2b4298409 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -538,7 +538,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) + if(layeridx == 0 && mNonAccumRoot) { for(size_t i = 0;i < objlist.mControllers.size();i++) { @@ -601,14 +601,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(mLayer[layeridx].mNextKey->first > targetTime) { mLayer[layeridx].mTime = targetTime; - if(layeridx == 0 && mNonAccumRoot) + if(layeridx == 0 && mNonAccumCtrl) movement += updatePosition(); break; } NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); mLayer[layeridx].mTime = key->first; - if(layeridx == 0 && mNonAccumRoot) + if(layeridx == 0 && mNonAccumCtrl) movement += updatePosition(); mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); From 102b3bdef99d0d7ea1ee601565d3463a7cb5212d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 01:57:51 -0700 Subject: [PATCH 1149/1483] Update position by reference --- apps/openmw/mwrender/animation.cpp | 13 +++++++------ apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a2b4298409..a8b2a18979 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -392,18 +392,19 @@ void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Og } -Ogre::Vector3 Animation::updatePosition() +void Animation::updatePosition(Ogre::Vector3 &position) { Ogre::Vector3 posdiff; - /* Get the non-accumulation root's difference from the last update. */ + /* Get the non-accumulation root's difference from the last update, and move the position + * accordingly. + */ posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; + position += posdiff; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; mAccumRoot->setPosition(-mLastPosition); - - return posdiff; } bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) @@ -602,14 +603,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) { mLayer[layeridx].mTime = targetTime; if(layeridx == 0 && mNonAccumCtrl) - movement += updatePosition(); + updatePosition(movement); break; } NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); mLayer[layeridx].mTime = key->first; if(layeridx == 0 && mNonAccumCtrl) - movement += updatePosition(); + updatePosition(movement); mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); timepassed = targetTime - mLayer[layeridx].mTime; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4860f44f5c..a874cb1a8e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -88,7 +88,7 @@ protected: /* Updates the position of the accum root node for the current time, and * returns the wanted movement vector from the previous update. */ - Ogre::Vector3 updatePosition(); + void updatePosition(Ogre::Vector3 &position); static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); From 68a9a4de5f77153f16e41fea47654b722fa6119d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:12:27 -0700 Subject: [PATCH 1150/1483] Fix setting and getting KeyframeController transforms --- components/nifogre/ogrenifloader.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 57aa794038..d36199f867 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -173,8 +173,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -193,8 +191,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -213,8 +209,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::QuaternionKeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -241,21 +235,21 @@ public: { if(mRotations.mKeys.size() > 0) return interpKey(mRotations.mKeys, time); - return Ogre::Quaternion(); + return mNode->getOrientation(); } virtual Ogre::Vector3 getTranslation(float time) const { if(mTranslations.mKeys.size() > 0) return interpKey(mTranslations.mKeys, time); - return Ogre::Vector3(0.0f); + return mNode->getPosition(); } virtual Ogre::Vector3 getScale(float time) const { if(mScales.mKeys.size() > 0) return Ogre::Vector3(interpKey(mScales.mKeys, time)); - return Ogre::Vector3(1.0f); + return mNode->getScale(); } virtual Ogre::Real getValue() const @@ -266,9 +260,12 @@ public: virtual void setValue(Ogre::Real time) { - mNode->setOrientation(Value::getRotation(time)); - mNode->setPosition(Value::getTranslation(time)); - mNode->setScale(Value::getScale(time)); + if(mRotations.mKeys.size() > 0) + mNode->setOrientation(interpKey(mRotations.mKeys, time)); + if(mTranslations.mKeys.size() > 0) + mNode->setPosition(interpKey(mTranslations.mKeys, time)); + if(mScales.mKeys.size() > 0) + mNode->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); } }; From 7241267d5c036f8c052598c18f04bdb8fef0b70e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:41:52 -0700 Subject: [PATCH 1151/1483] Make an AnimationValue for each animation layer --- apps/openmw/mwrender/animation.cpp | 8 +++--- apps/openmw/mwrender/animation.hpp | 40 ++++++++++++++++-------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a8b2a18979..3d938cc258 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -58,8 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) - , mPtr(ptr) + : mPtr(ptr) , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) @@ -71,6 +70,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + for(size_t i = 0;i < sMaxLayers;i++) + mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this, i)); + /* As long as we remain under 128 active controllers, we can avoid * reallocations. */ mActiveCtrls.reserve(128); @@ -153,7 +155,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b for(size_t i = 0;i < objlist.mControllers.size();i++) { if(objlist.mControllers[i].getSource().isNull()) - objlist.mControllers[i].setSource(mAnimationBaseValuePtr); + objlist.mControllers[i].setSource(mAnimationValuePtr[0]); } mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a874cb1a8e..282cd3eca2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,10 +33,6 @@ protected: virtual Ogre::Real getValue() const; virtual void setValue(Ogre::Real value); }; - Ogre::SharedPtr > mAnimationBaseValuePtr; - - MWWorld::Ptr mPtr; - MWMechanics::CharacterController *mController; struct ObjectInfo { NifOgre::ObjectList mObjectList; @@ -47,20 +43,6 @@ protected: int mActiveLayers; }; - Ogre::SceneNode *mInsert; - Ogre::Entity *mSkelBase; - std::vector mObjects; - Ogre::Node *mAccumRoot; - Ogre::Bone *mNonAccumRoot; - Ogre::Vector3 mAccumulate; - Ogre::Vector3 mLastPosition; - - NifOgre::NodeTargetValue *mNonAccumCtrl; - float mAnimVelocity; - float mAnimSpeedMult; - std::vector > mActiveCtrls; - - static const size_t sMaxLayers = 1; struct AnimLayer { std::string mGroupName; std::vector > *mControllers; @@ -76,7 +58,27 @@ protected: bool mLooping; AnimLayer(); - } mLayer[sMaxLayers]; + }; + + MWWorld::Ptr mPtr; + MWMechanics::CharacterController *mController; + + Ogre::SceneNode *mInsert; + Ogre::Entity *mSkelBase; + std::vector mObjects; + Ogre::Node *mAccumRoot; + Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mAccumulate; + Ogre::Vector3 mLastPosition; + + NifOgre::NodeTargetValue *mNonAccumCtrl; + float mAnimVelocity; + float mAnimSpeedMult; + std::vector > mActiveCtrls; + + static const size_t sMaxLayers = 1; + AnimLayer mLayer[sMaxLayers]; + Ogre::SharedPtr > mAnimationValuePtr[sMaxLayers]; static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, From c58dfbe921cda569f950648f3307145a9c2cfe37 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:56:39 -0700 Subject: [PATCH 1152/1483] Specify the loop count to Animation::play --- apps/openmw/mwmechanics/character.cpp | 12 ++++++------ apps/openmw/mwrender/animation.cpp | 19 ++++++++++++------- apps/openmw/mwrender/animation.hpp | 6 +++--- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 07f7b69401..664ed7c032 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } CharacterController::CharacterController(const CharacterController &rhs) @@ -155,7 +155,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", 0); } return; } @@ -164,7 +164,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", 0); } else if(mAnimQueue.size() > 0) { @@ -172,7 +172,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", "stop", false); + mAnimation->play(mCurrentGroup, "start", "stop", 0); } } return; @@ -284,7 +284,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", false); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0); } else if(mode == 0) { @@ -316,7 +316,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3d938cc258..4e82f0b8c3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,7 +23,7 @@ Animation::AnimLayer::AnimLayer() , mTextKeys(NULL) , mTime(0.0f) , mPlaying(false) - , mLooping(false) + , mLoopCount(0) { } @@ -449,14 +449,20 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: return true; } -void Animation::doLoop(size_t layeridx) +bool Animation::doLoop(size_t layeridx) { + if(mLayer[layeridx].mLoopCount == 0) + return false; + mLayer[layeridx].mLoopCount--; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; mLayer[layeridx].mNextKey++; mLayer[layeridx].mPlaying = true; if(layeridx == 0 && mNonAccumCtrl) mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; + + return true; } @@ -495,9 +501,8 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLayer[layeridx].mLooping) + if(doLoop(layeridx)) { - doLoop(layeridx); if(mLayer[layeridx].mTime >= time) return false; return true; @@ -510,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -527,7 +532,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName.clear(); mLayer[layeridx].mTextKeys = NULL; mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; + mLayer[layeridx].mLoopCount = 0; mLayer[layeridx].mPlaying = false; foundanim = true; @@ -562,7 +567,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mLoopCount = loops; mLayer[layeridx].mPlaying = true; if(layeridx == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 282cd3eca2..1b300887fc 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,7 +55,7 @@ protected: float mTime; bool mPlaying; - bool mLooping; + size_t mLoopCount; AnimLayer(); }; @@ -101,7 +101,7 @@ protected: */ bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(size_t layeridx); + bool doLoop(size_t layeridx); bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); @@ -129,7 +129,7 @@ public: void setSpeed(float speed); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); + void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); Ogre::Node *getNode(const std::string &name); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 41770d4891..c22d8a4da4 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -155,7 +155,7 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", false); + mAnimation->play("inventoryhandtohand", "start", "stop", 0); } // -------------------------------------------------------------------------------------------------- @@ -189,7 +189,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", false); + mAnimation->play("idle", "start", "stop", 0); updateCamera(); } From b482d5be097b16a8df8ecc04c8b25252e81e746c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 05:23:45 -0700 Subject: [PATCH 1153/1483] Add a method to check if a given layer is playing --- apps/openmw/mwrender/animation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1b300887fc..87c57ebf7b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -132,6 +132,9 @@ public: void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); + bool isPlaying(size_t layeridx) const + { return mLayer[layeridx].mPlaying; } + Ogre::Node *getNode(const std::string &name); }; From e8cabc94349d95bbb9e23a3604e8d1afe85ed8b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 06:32:11 -0700 Subject: [PATCH 1154/1483] Pass the loop count from loopgroup to the play method Instead of queueing each iteration separately. --- apps/openmw/mwmechanics/character.cpp | 34 +++++++-------------------- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 11 ++++++++- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 664ed7c032..086a2fc252 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -150,29 +150,16 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::markerEvent(float time, const std::string &evt) { - if(evt == "loop stop") - { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", 0); - } - return; - } if(evt == "stop") { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", 0); - } - else if(mAnimQueue.size() > 0) + if(mAnimQueue.size() > 0) { mAnimQueue.pop_front(); if(mAnimQueue.size() > 0) { - mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", "stop", 0); + mCurrentGroup = mAnimQueue.front().first; + size_t count = mAnimQueue.front().second; + mAnimation->play(mCurrentGroup, "start", "stop", count); } } return; @@ -223,7 +210,6 @@ void CharacterController::update(float duration, Movement &movement) if(vec.x > 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight) : (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight)), true); - else if(vec.x < 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); @@ -236,10 +222,10 @@ void CharacterController::update(float duration, Movement &movement) if(vec.y > 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward) : (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward)), true); - else if(vec.y < 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true); + // Apply any sideways movement manually movement.mPosition[0] += vec.x * (speed*duration); } @@ -250,7 +236,7 @@ void CharacterController::update(float duration, Movement &movement) else if(rot.z < 0.0f) setState(CharState_TurnLeft, true); } - else if(mAnimQueue.size() == 0) + else if(getState() != CharState_SpecialIdle || !mAnimation->isPlaying(0)) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); movement.mRotation[0] += rot.x * duration; @@ -280,17 +266,15 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int if(mode != 0 || mAnimQueue.size() == 0) { mAnimQueue.clear(); - while(count-- > 0) - mAnimQueue.push_back(groupname); + mAnimQueue.push_back(std::make_pair(groupname, count-1)); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); } else if(mode == 0) { mAnimQueue.resize(1); - while(count-- > 0) - mAnimQueue.push_back(groupname); + mAnimQueue.push_back(std::make_pair(groupname, count-1)); } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 5b5a65f797..4453b078db 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -72,7 +72,7 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - typedef std::deque AnimationQueue; + typedef std::deque > AnimationQueue; AnimationQueue mAnimQueue; std::string mCurrentGroup; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4e82f0b8c3..b205d95192 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -499,7 +499,16 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ return true; } - if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) + if(evt.compare(off, len, "loop stop") == 0) + { + if(doLoop(layeridx)) + { + if(mLayer[layeridx].mTime >= time) + return false; + } + return true; + } + if(evt.compare(off, len, "stop") == 0) { if(doLoop(layeridx)) { From b80891099e0171af7a58dd9733b4abfd901fc3aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 06:48:34 -0700 Subject: [PATCH 1155/1483] Don't use the character controller to handle text keys The Animation class has the Ptr and can call to whatever subsystem is needed. --- apps/openmw/mwmechanics/character.cpp | 38 +++++++++------------------ apps/openmw/mwmechanics/character.hpp | 6 ----- apps/openmw/mwrender/animation.cpp | 16 +++-------- 3 files changed, 16 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 086a2fc252..bbf679cdae 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -148,27 +148,6 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) } -void CharacterController::markerEvent(float time, const std::string &evt) -{ - if(evt == "stop") - { - if(mAnimQueue.size() > 0) - { - mAnimQueue.pop_front(); - if(mAnimQueue.size() > 0) - { - mCurrentGroup = mAnimQueue.front().first; - size_t count = mAnimQueue.front().second; - mAnimation->play(mCurrentGroup, "start", "stop", count); - } - } - return; - } - - std::cerr<< "Unhandled animation event: "<isPlaying(0)) - setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + { + if(mAnimQueue.size() > 0) + { + mCurrentGroup = mAnimQueue.front().first; + size_t count = mAnimQueue.front().second; + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "start", "stop", count); + } + else + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + } movement.mRotation[0] += rot.x * duration; movement.mRotation[1] += rot.y * duration; @@ -263,17 +252,16 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int else { count = std::max(count, 1); - if(mode != 0 || mAnimQueue.size() == 0) + if(mode != 0 || getState() != CharState_SpecialIdle) { mAnimQueue.clear(); - mAnimQueue.push_back(std::make_pair(groupname, count-1)); mCurrentGroup = groupname; mState = CharState_SpecialIdle; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); } else if(mode == 0) { - mAnimQueue.resize(1); + mAnimQueue.clear(); mAnimQueue.push_back(std::make_pair(groupname, count-1)); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4453b078db..4bbea15519 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,12 +79,6 @@ class CharacterController CharacterState mState; bool mSkipAnim; -protected: - /* Called by the animation whenever a new text key is reached. */ - void markerEvent(float time, const std::string &evt); - - friend class MWRender::Animation; - public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b205d95192..c0fee0d3b6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -499,7 +499,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ return true; } - if(evt.compare(off, len, "loop stop") == 0) + if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { if(doLoop(layeridx)) { @@ -508,18 +508,8 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } return true; } - if(evt.compare(off, len, "stop") == 0) - { - if(doLoop(layeridx)) - { - if(mLayer[layeridx].mTime >= time) - return false; - return true; - } - // fall-through - } - if(mController) - mController->markerEvent(time, evt.substr(off)); + + std::cerr<< "Unhandled animation textkey: "< Date: Wed, 24 Apr 2013 07:10:41 -0700 Subject: [PATCH 1156/1483] Remove the character controller from the Animation class --- apps/openmw/mwmechanics/character.cpp | 13 ------------- apps/openmw/mwmechanics/character.hpp | 1 - apps/openmw/mwrender/animation.cpp | 9 +-------- apps/openmw/mwrender/animation.hpp | 12 +++--------- 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bbf679cdae..2a7ab8b09b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -108,8 +108,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; - mAnimation->setController(this); - getStateInfo(mState, &mCurrentGroup); if(MWWorld::Class::get(mPtr).isActor()) { @@ -126,17 +124,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } -CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) - , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) - , mSkipAnim(rhs.mSkipAnim) -{ - if(!mAnimation) - return; - /* We've been copied. Update the animation with the new controller. */ - mAnimation->setController(this); -} - CharacterController::~CharacterController() { } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4bbea15519..ffd220ff2f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -81,7 +81,6 @@ class CharacterController public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); - CharacterController(const CharacterController &rhs); virtual ~CharacterController(); void updatePtr(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0fee0d3b6..c2f4535164 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -59,14 +59,13 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) - , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mNonAccumCtrl(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { @@ -299,12 +298,6 @@ bool Animation::hasAnimation(const std::string &anim) } -void Animation::setController(MWMechanics::CharacterController *controller) -{ - mController = controller; -} - - void Animation::setAccumulation(const Ogre::Vector3 &accum) { mAccumulate = accum; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 87c57ebf7b..526bca69a8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -8,10 +8,6 @@ #include "../mwworld/ptr.hpp" -namespace MWMechanics -{ - class CharacterController; -} namespace MWRender { @@ -61,20 +57,20 @@ protected: }; MWWorld::Ptr mPtr; - MWMechanics::CharacterController *mController; Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; std::vector mObjects; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; + NifOgre::NodeTargetValue *mNonAccumCtrl; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - NifOgre::NodeTargetValue *mNonAccumCtrl; + std::vector > mActiveCtrls; + float mAnimVelocity; float mAnimSpeedMult; - std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; AnimLayer mLayer[sMaxLayers]; @@ -116,8 +112,6 @@ public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); - void setController(MWMechanics::CharacterController *controller); - void updatePtr(const MWWorld::Ptr &ptr); bool hasAnimation(const std::string &anim); From 53fb17da10436022178562d5d573659f769e0102 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 24 Apr 2013 21:42:04 +0200 Subject: [PATCH 1157/1483] Rotation system fixes --- apps/openmw/mwscript/transformationextensions.cpp | 9 +++------ apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index beb6c3d8c1..f2179897dc 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -153,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -563,17 +563,14 @@ namespace MWScript if (axis == "x") { - ptr.getRefData().getLocalRotation().rot[0]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { - ptr.getRefData().getLocalRotation().rot[1]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { - ptr.getRefData().getLocalRotation().rot[2]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 69bcad619d..aa9107c6ec 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -827,6 +827,14 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) { if (ptr.getRefData().getBaseNode() != 0) { + + if(axis==Ogre::Vector3::UNIT_X) + ptr.getRefData().getLocalRotation().rot[0]+=rotation; + else if(axis==Ogre::Vector3::UNIT_Y) + ptr.getRefData().getLocalRotation().rot[1]+=rotation; + else if(axis==Ogre::Vector3::UNIT_Z) + ptr.getRefData().getLocalRotation().rot[2]+=rotation; + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); mPhysics->rotateObject(ptr); } From c0102954f1d435b21aa2e6a7f1b6d61207ac925b Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 30 Mar 2013 13:28:17 +0100 Subject: [PATCH 1158/1483] Add non-breaking space to font code range --- files/mygui/openmw_font.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index b1446fae14..f1be51e165 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -9,6 +9,7 @@ + From cd57e3f896260e480db9fab1aa0d0b9e03f2aa09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 23:51:43 +0200 Subject: [PATCH 1159/1483] Auto calculate attributes if there are not specified in the NPC record --- apps/openmw/mwclass/npc.cpp | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7cda87bb15..ea49ae4a4c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,67 @@ namespace { return new CustomData (*this); } + + void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) + { + // race bonus + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mRace); + + bool male = (npc->mFlags & ESM::NPC::Female) == 0; + + int level = creatureStats.getLevel(); + + for (int i=0; imData.mAttributeValues[i]; + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); + } + + // class bonus + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mClass); + + for (int i=0; i<2; ++i) + { + int attribute = class_->mData.mAttribute[i]; + if (attribute>=0 && attribute<8) + { + creatureStats.getAttribute(attribute).setBase ( + creatureStats.getAttribute(attribute).getBase() + 10); + } + } + + // skill bonus + for (int attribute=0; attributegetStore().get().find(j); + + if (skill->mData.mAttribute != attribute) + continue; + + // is this a minor or major skill? + float add=0.2; + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][0] == j) + add=0.5; + } + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][1] == j) + add=1.0; + } + modifierSum += add; + } + creatureStats.getAttribute(attribute).setBase ( std::min(creatureStats.getAttribute(attribute).getBase() + + static_cast((level-1) * modifierSum+0.5), 100) ); + } + } } namespace MWClass @@ -126,15 +187,14 @@ namespace MWClass } else { - for (int i=0; i<8; ++i) - data->mCreatureStats.getAttribute (i).set (10); - for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + + autoCalculateAttributes(ref->mBase, data->mCreatureStats); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 2c8b0a154175f3320fe4e082a5208d538f707875 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 00:26:36 +0200 Subject: [PATCH 1160/1483] last minute change to changelog --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 5f38457765..d5a5dcc183 100644 --- a/readme.txt +++ b/readme.txt @@ -136,6 +136,7 @@ Bug #700: "On the rocks" mod does not load its UV coordinates correctly. Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon +Bug #725: Auto calculate stats Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From 21bdcc9f20d14e7d5aabf906860cee573e0e31a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 01:33:04 +0200 Subject: [PATCH 1161/1483] Only use the shader based mygui manager if the fixed pipeline is unavailable --- libs/openengine/gui/manager.cpp | 30 ++++++++++++++++++++++++++---- libs/openengine/gui/manager.hpp | 5 +++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index f9117586fe..a0a4ab0aea 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -559,6 +559,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool assert(mgr); mSceneMgr = mgr; + mShaderRenderManager = NULL; + mRenderManager = NULL; using namespace MyGUI; @@ -574,7 +576,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new MyGUI::ShaderBasedRenderManager(); + if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) + mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); + else + mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); @@ -582,7 +587,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool if (!theLogFile.empty()) LogManager::getInstance().createDefaultSource(theLogFile); - mRenderManager->initialise(wnd, mgr); + if (mShaderRenderManager) + mShaderRenderManager->initialise(wnd, mgr); + else + mRenderManager->initialise(wnd, mgr); mDataManager->initialise("General"); // Create GUI @@ -592,8 +600,16 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) { - mRenderManager->setRenderWindow (wnd); - mRenderManager->setActiveViewport(0); + if (mShaderRenderManager) + { + mShaderRenderManager->setRenderWindow (wnd); + mShaderRenderManager->setActiveViewport(0); + } + else + { + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); + } } void MyGUIManager::shutdown() @@ -606,6 +622,12 @@ void MyGUIManager::shutdown() delete mRenderManager; mRenderManager = NULL; } + if(mShaderRenderManager) + { + mShaderRenderManager->shutdown(); + delete mShaderRenderManager; + mShaderRenderManager = NULL; + } if(mDataManager) { mDataManager->shutdown(); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index eec867ff8b..9535f2a24e 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,6 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; + class OgreRenderManager; class ShaderBasedRenderManager; } @@ -25,12 +26,12 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::ShaderBasedRenderManager* mRenderManager; + MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mShaderRenderManager; Ogre::SceneManager* mSceneMgr; public: - MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL), mGui(NULL) {} MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) { setup(wnd,mgr,logging, logDir); From 87ce2110dcc912394a6d49599a7bb7558bac68a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 14:41:26 +0200 Subject: [PATCH 1162/1483] hotfix for CharacterPreview destructor --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8396acaea8..41770d4891 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -21,13 +21,15 @@ namespace MWRender CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mSizeX(sizeX) - , mSizeY(sizeY) - , mName(name) + + : mSceneMgr (0) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) + , mName(name) + , mSizeX(sizeX) + , mSizeY(sizeY) { } @@ -88,16 +90,20 @@ namespace MWRender CharacterPreview::~CharacterPreview () { - //Ogre::TextureManager::getSingleton().remove(mName); - mSceneMgr->destroyCamera (mName); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneMgr) + { + //Ogre::TextureManager::getSingleton().remove(mName); + mSceneMgr->destroyAllCameras(); + delete mAnimation; + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + } } void CharacterPreview::rebuild() { assert(mAnimation); delete mAnimation; + mAnimation = 0; mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); From 51580ead4f9c20f8b683384c618c5f1b25c2afd7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 17:57:22 +0200 Subject: [PATCH 1163/1483] Fix consecutive dialogue choices --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 9380ab76cd..220adf566a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -426,6 +426,7 @@ namespace MWDialogue void DialogueManager::questionAnswered (const std::string& answer) { + if (mChoiceMap.find(answer) != mChoiceMap.end()) { mChoice = mChoiceMap[answer]; @@ -442,6 +443,10 @@ namespace MWDialogue std::string text = info->mResponse; parseText (text); + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); @@ -449,9 +454,6 @@ namespace MWDialogue mLastDialogue = *info; } } - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; } updateTopics(); From 2dc01fe56b923c382ebfe7da5c1829d8580bb450 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 21 Apr 2013 11:41:09 -0700 Subject: [PATCH 1164/1483] fixed the type of iterator uses in MWWorld::Store The containers type used to declare some iterators was not an exact match for the type of the container the iterator was being initialized from. This was causing build failure on windows. --- apps/openmw/mwworld/store.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 959b944e10..7949cbe002 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -475,7 +475,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -493,7 +493,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -534,7 +534,7 @@ namespace MWWorld void setUp() { //typedef std::vector::iterator Iterator; - typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef DynamicExt::iterator ExtIterator; typedef std::map::iterator IntIterator; //std::sort(mInt.begin(), mInt.end(), RecordCmp()); From a7092ef2d709a575848451ade18e45e360f80f09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Apr 2013 21:24:48 +0200 Subject: [PATCH 1165/1483] Fix activation not working sometimes The current player cell was only being updated when the reference was not empty, causing it to incorrectly detect a cell change the first time something was activated in a newly visited cell, immediately closing the opened dialogue again. --- apps/openmw/mwgui/referenceinterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 66e036d929..86a85be18e 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -18,17 +18,17 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - if (mPtr.isEmpty()) - return; - MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) - || mPtr.getRefData().getCount() == 0) + || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) { - mPtr = MWWorld::Ptr(); - onReferenceUnavailable(); + if (!mPtr.isEmpty()) + { + mPtr = MWWorld::Ptr(); + onReferenceUnavailable(); + } } mCurrentPlayerCell = playerCell; From baa7a9160c35b4ce13dde8666a2039eb998354e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Apr 2013 07:57:53 +0200 Subject: [PATCH 1166/1483] Rank condition should always fail if NPC is not in a faction --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 78969ffd0b..52c7bd4f34 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -73,6 +73,11 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (iter->second < info.mData.mRank) return false; } + else if (info.mData.mRank != -1) + { + // if there is a rank condition, but the NPC is not in a faction, always fail + return false; + } // Gender if (!isCreature) From 8d0e5fc0c4b7272508309e4325ab6c5590b2aa8b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 22 Apr 2013 09:56:11 +0200 Subject: [PATCH 1167/1483] updated changelog once more --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index d5a5dcc183..c033f95475 100644 --- a/readme.txt +++ b/readme.txt @@ -137,6 +137,8 @@ Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon Bug #725: Auto calculate stats +Bug #728: Failure to open container and talk dialogue +Bug #731: Crash with Mush-Mere's "background" topic Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From ad05f238deaec2679336e7d0c35366b53cdfa4c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Apr 2013 22:47:21 +0200 Subject: [PATCH 1168/1483] Use one vertex buffer for all UV coordinates --- components/nifogre/mesh.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c30..6d940deed3 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -260,13 +260,24 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Texture UV coordinates size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) + if (numUVs) { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + + for(size_t i = 0; i < numUVs; i++) + decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + + vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + + std::vector allUVs; + allUVs.reserve(srcVerts.size()*numUVs); + for (size_t vert = 0; vertuvlist[i][vert]); + + vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); bind->setBinding(nextBuf++, vbuf); } From 933f89414842eaa566803bb6ed506e85380fd2e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Apr 2013 02:31:51 +0200 Subject: [PATCH 1169/1483] Added Blind and Night Eye effects --- apps/openmw/mwrender/renderingmanager.cpp | 27 ++++++++++++++++------- libs/openengine/ogre/fader.cpp | 12 +++++----- libs/openengine/ogre/fader.hpp | 4 ++++ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 029cf394b4..da51f10c1c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -30,6 +30,8 @@ #include "../mwbase/inputmanager.hpp" // FIXME #include "../mwbase/windowmanager.hpp" // FIXME +#include "../mwmechanics/creaturestats.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/player.hpp" @@ -315,13 +317,15 @@ void RenderingManager::update (float duration, bool paused) { MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; + mRendering.getFader()->setFactor(1.f-(blind / 100.f)); + + setAmbientMode(); + // player position - MWWorld::RefData &data = - MWBase::Environment::get() - .getWorld() - ->getPlayer() - .getPlayer() - .getRefData(); + MWWorld::RefData &data = player.getRefData(); float *_playerPos = data.getPosition().pos; Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); @@ -597,8 +601,15 @@ void RenderingManager::setSunColour(const Ogre::ColourValue& colour) void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) { - mRendering.getScene()->setAmbientLight(colour); - mTerrainManager->setAmbient(colour); + mAmbientColor = colour; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int nightEye = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::NightEye)).mMagnitude; + Ogre::ColourValue final = colour; + final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); + + mRendering.getScene()->setAmbientLight(final); + mTerrainManager->setAmbient(final); } void RenderingManager::sunEnable(bool real) diff --git a/libs/openengine/ogre/fader.cpp b/libs/openengine/ogre/fader.cpp index 9390d06647..923b0b7e38 100644 --- a/libs/openengine/ogre/fader.cpp +++ b/libs/openengine/ogre/fader.cpp @@ -19,6 +19,7 @@ Fader::Fader(Ogre::SceneManager* sceneMgr) , mTargetAlpha(0.f) , mCurrentAlpha(0.f) , mStartAlpha(0.f) + , mFactor(1.f) { // Create the fading material MaterialPtr material = MaterialManager::getSingleton().create("FadeInOutMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); @@ -62,19 +63,20 @@ void Fader::update(float dt) mCurrentAlpha += dt/mTargetTime * (mTargetAlpha-mStartAlpha); if (mCurrentAlpha > mTargetAlpha) mCurrentAlpha = mTargetAlpha; } - - applyAlpha(); - + mRemainingTime -= dt; } - if (mCurrentAlpha == 0.f) mRectangle->setVisible(false); + if (1.f-((1.f-mCurrentAlpha) * mFactor) == 0.f) + mRectangle->setVisible(false); + else + applyAlpha(); } void Fader::applyAlpha() { mRectangle->setVisible(true); - mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, mCurrentAlpha); + mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 1.f-((1.f-mCurrentAlpha) * mFactor)); } void Fader::fadeIn(float time) diff --git a/libs/openengine/ogre/fader.hpp b/libs/openengine/ogre/fader.hpp index bddf5dc919..53124e2f65 100644 --- a/libs/openengine/ogre/fader.hpp +++ b/libs/openengine/ogre/fader.hpp @@ -29,6 +29,8 @@ namespace Render void fadeOut(const float time); void fadeTo(const int percent, const float time); + void setFactor (float factor) { mFactor = factor; } + private: enum FadingMode { @@ -49,6 +51,8 @@ namespace Render float mCurrentAlpha; float mStartAlpha; + float mFactor; + Ogre::SceneManager* mSceneMgr; }; }} From 0817d59f23d4b2f36711109696c87cf6c22ad672 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 19:09:36 -0700 Subject: [PATCH 1170/1483] Allow specifying where to start in an animation --- apps/openmw/mwmechanics/character.cpp | 14 +++++++------- apps/openmw/mwrender/animation.cpp | 18 +++++++++++++----- apps/openmw/mwrender/animation.hpp | 18 ++++++++++++++++-- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2a7ab8b09b..9397b2e356 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -121,7 +121,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); + mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); } CharacterController::~CharacterController() @@ -204,15 +204,15 @@ void CharacterController::update(float duration, Movement &movement) } else if(getState() != CharState_SpecialIdle || !mAnimation->isPlaying(0)) { - if(mAnimQueue.size() > 0) + if(mAnimQueue.size() == 0) + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + else { mCurrentGroup = mAnimQueue.front().first; size_t count = mAnimQueue.front().second; mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "start", "stop", count); + mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); } - else - setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); } movement.mRotation[0] += rot.x * duration; @@ -244,7 +244,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) { @@ -275,7 +275,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); + mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2f4535164..0f509d2767 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -402,7 +402,7 @@ void Animation::updatePosition(Ogre::Vector3 &position) mAccumRoot->setPosition(-mLastPosition); } -bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -432,9 +432,17 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: mLayer[layeridx].mLoopStartKey = startkey; mLayer[layeridx].mStopKey = stopkey; mLayer[layeridx].mNextKey = startkey; - mLayer[layeridx].mNextKey++; - mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first + ((mLayer[layeridx].mStopKey->first- + mLayer[layeridx].mStartKey->first) * startpoint); + + tag = groupname+": loop start"; + while(mLayer[layeridx].mNextKey->first <= mLayer[layeridx].mTime && mLayer[layeridx].mNextKey != mLayer[layeridx].mStopKey) + { + if(mLayer[layeridx].mNextKey->second == tag) + mLayer[layeridx].mLoopStartKey = mLayer[layeridx].mNextKey; + mLayer[layeridx].mNextKey++; + } if(layeridx == 0 && nonaccumctrl) mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; @@ -507,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -554,7 +562,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!foundanim) { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop, startpoint)) continue; mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 526bca69a8..d7f38545f5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -95,7 +95,10 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, + NifOgre::NodeTargetValue *nonaccumctrl, + const std::string &groupname, const std::string &start, const std::string &stop, + float startpoint); bool doLoop(size_t layeridx); @@ -123,7 +126,18 @@ public: void setSpeed(float speed); - void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); + /** Plays an animation. + * \param groupname Name of the animation group to play. + * \param start Key marker from which to start. + * \param stop Key marker to stop at. + * \param startpoint How far in between the two markers to start. 0 starts + * at the start marker, 1 starts at the stop marker. + * \param loops How many times to loop the animation. This will use the + * "loop start" and "loop stop" markers if they exist, + * otherwise it will use "start" and "stop". + */ + void play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); + virtual Ogre::Vector3 runAnimation(float timepassed); bool isPlaying(size_t layeridx) const diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index c22d8a4da4..24b089db38 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -155,7 +155,7 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", 0); + mAnimation->play("inventoryhandtohand", "start", "stop", 0.0f, 0); } // -------------------------------------------------------------------------------------------------- @@ -189,7 +189,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", 0); + mAnimation->play("idle", "start", "stop", 0.0f, 0); updateCamera(); } From 9e3917881d5d4f0b1c23c31d879369a06a9bc4bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Apr 2013 04:44:30 +0200 Subject: [PATCH 1171/1483] Don't fail on nonexistent items in a levelled list --- apps/openmw/mwworld/containerstore.cpp | 85 ++++++++++++++------------ 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 05026a98ba..5cf5342393 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -193,59 +193,68 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + try { - const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - const std::vector& items = levItem->mList; + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); - - failChance += levItem->mChanceNone; - - if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { - for (int i=0; i()->mBase; + const std::vector& items = levItem->mList; - float random = static_cast (std::rand()) / RAND_MAX; - if (random >= failChance/100.f) - { - std::vector candidates; - int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); + + failChance += levItem->mChanceNone; + + if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { - if (it->mLevel > highestLevel) - highestLevel = it->mLevel; + for (int i=0; i highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + float random = static_cast (std::rand()) / RAND_MAX; + if (random >= failChance/100.f) { - if (playerLevel >= it->mLevel - && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + std::vector candidates; + int highestLevel = 0; + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { - candidates.push_back(it->mId); - if (it->mLevel >= highest.first) - highest = std::make_pair(it->mLevel, it->mId); + if (it->mLevel > highestLevel) + highestLevel = it->mLevel; } + std::pair highest = std::make_pair(-1, ""); + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (playerLevel >= it->mLevel + && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + { + candidates.push_back(it->mId); + if (it->mLevel >= highest.first) + highest = std::make_pair(it->mLevel, it->mId); + } + + } + if (!candidates.size()) + return; + std::string item = candidates[std::rand()%candidates.size()]; + addInitialItem(item, owner, count, failChance, false); } - if (!candidates.size()) - return; - std::string item = candidates[std::rand()%candidates.size()]; - addInitialItem(item, owner, count, failChance, false); + } + else + { + ref.getPtr().getRefData().setCount (count); + ref.getPtr().getCellRef().mOwner = owner; + addImp (ref.getPtr()); } } - else + catch (std::logic_error& e) { - ref.getPtr().getRefData().setCount (count); - ref.getPtr().getCellRef().mOwner = owner; - addImp (ref.getPtr()); + // Vanilla doesn't fail on nonexistent items in levelled lists + std::cerr << "Warning: ignoring nonexistent item '" << id << "'" << std::endl; + return; } } From 03ee7663a3e89698c36108d03a7fcd036762d827 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 17:33:28 -0800 Subject: [PATCH 1172/1483] reworked NIFStream to use a type-handler Reworked NIFStream to use a type-handler system to decide how to extract data from the NIF. It also has the capability to perform bulk reads on compatible platforms, thus improving cell-load performance. --- components/nif/nifstream.hpp | 338 +++++++++++++++++++++++------------ 1 file changed, 225 insertions(+), 113 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index a2595d17b8..7abfae9e84 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP +#include + namespace Nif { @@ -11,168 +13,278 @@ class NIFStream { /// Input stream Ogre::DataStreamPtr inp; - uint8_t read_byte() + template + value_t read_le () { - uint8_t byte; - if(inp->read(&byte, 1) != 1) return 0; - return byte; - } - uint16_t read_le16() - { - uint8_t buffer[2]; - if(inp->read(buffer, 2) != 2) return 0; - return buffer[0] | (buffer[1]<<8); - } - uint32_t read_le32() - { - uint8_t buffer[4]; - if(inp->read(buffer, 4) != 4) return 0; - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); - } - float read_le32f() - { - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; + uint8_t buffer [sizeof (value_t)]; + + if (inp->read (buffer, sizeof (buffer)) != sizeof (buffer)) + throw std::runtime_error ("unexpected"); + + value_t Value = 0; + value_t Shift = 0; + + for (size_t i = 0; i < sizeof (value_t); ++i) + { + Value |= value_t (buffer[i]) << Shift; + Shift += 8; + } + + return Value; } public: + /* + * This should be true for any processor/platform whose endianess, alignment + * and packing rules would be compatible with x86 and not fault or degrade + * with misaligned reads. This enables some pretty big savings when reading in + * animations and meshes. + */ +#if defined (__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) + static const bool FileCompatiblePlatform = true; +#else + static const bool FileCompatiblePlatform = false; +#endif + + template + struct handler; + + template + struct le_handler; + + template + friend struct le_handler; + + template + struct conversion_handler; + NIFFile * const file; - NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + NIFStream (NIFFile * file, Ogre::DataStreamPtr inp) : file (file), inp (inp) {} /************************************************* Parser functions ****************************************************/ - template - struct GetHandler - { - typedef T (NIFStream::*fn_t)(); - - static const fn_t sValue; // this is specialized per supported type in the .cpp file - - static T read (NIFStream* nif) - { - return (nif->*sValue) (); - } - }; + void skip(size_t size) { return inp->skip (size); } + size_t read (void * data, size_t size) { return inp->read (data, size); } template - void read (NIFStream* nif, T & Value) + void uncheckedRead (T & Value) { - Value = GetHandler ::read (nif); + typedef handler handler_t; + handler_t::extract (*this, Value); } - void skip(size_t size) { inp->skip(size); } - void read (void * data, size_t size) { inp->read (data, size); } + template + T getValue () + { + T Value; + getValue (Value); + return Value; + } - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - int getUInt() { return read_le32(); } - float getFloat() { return read_le32f(); } - Ogre::Vector2 getVector2() + template + void getValue (T & Value) { - float a[2]; - for(size_t i = 0;i < 2;i++) - a[i] = getFloat(); - return Ogre::Vector2(a); - } - Ogre::Vector3 getVector3() - { - float a[3]; - for(size_t i = 0;i < 3;i++) - a[i] = getFloat(); - return Ogre::Vector3(a); - } - Ogre::Vector4 getVector4() - { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Vector4(a); - } - Ogre::Matrix3 getMatrix3() - { - Ogre::Real a[3][3]; - for(size_t i = 0;i < 3;i++) + typedef handler handler_t; + if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) { - for(size_t j = 0;j < 3;j++) - a[i][j] = Ogre::Real(getFloat()); + BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); + BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (T), "unexpected structure size"); + + inp->read (&Value, handler_t::EncodedLength); + } + else + { + handler_t::extract (*this, Value); } - return Ogre::Matrix3(a); } - Ogre::Quaternion getQuaternion() + + template + void getArray (element_type * Array, size_t Size) { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Quaternion(a); + typedef handler handler_t; + + if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) + { + BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); + BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (element_type), "unexpected structure size"); + + inp->read (Array, handler_t::EncodedLength * Size); + } + else + { + for(size_t i = 0; i < Size; i++) + handler_t::extract (*this, Array[i]); + } } - Transformation getTrafo() + + template + void getStdVector (std::vector & Vector, size_t Size) { - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; + Vector.resize(Size); + + getArray (&Vector.front (), Vector.size ()); } + template + void getStdVector (std::vector & Vector) + { + length_type Length; + + getValue (Length); + + getStdVector (Vector, Length); + } + + char getChar() { return getValue (); } + signed int getInt() { return getValue (); } + unsigned int getUInt() { return getValue (); } + signed short getShort() { return getValue (); } + unsigned short getUShort() { return getValue (); } + //signed long getLong() { return getValue (); } + //unsigned long getULong() { return getValue (); } + float getFloat() { return getValue (); } + + Ogre::Vector2 getVector2() { return getValue (); } + Ogre::Vector3 getVector3() { return getValue (); } + Ogre::Vector4 getVector4() { return getValue (); } + Ogre::Matrix3 getMatrix3() { return getValue (); } + Ogre::Quaternion getQuaternion() { return getValue (); } + + Transformation getTrafo() { return getValue (); } + + void getShorts(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getFloats(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector2s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector3s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector4s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getQuaternions(std::vector &vec, size_t size) { return getStdVector (vec, size); } + std::string getString(size_t length) { std::vector str (length+1, 0); - if(inp->read(&str[0], length) != length) + if(read(&str[0], length) != length) throw std::runtime_error ("string length in NIF file does not match"); return &str[0]; } std::string getString() { - size_t size = read_le32(); + size_t size = getValue (); return getString(size); } +}; - void getShorts(std::vector &vec, size_t size) +/* + * generic type handlers + */ + +template +struct NIFStream::handler < type [Size] > +{ + typedef handler inner_handler; + + static const bool FixedLength = inner_handler::FixedLength; + static const size_t EncodedLength = inner_handler::EncodedLength * Size; + static const bool FileCompatibleLayout = inner_handler::FileCompatibleLayout; + + static void extract (NIFStream & Stream, type (&Value) [Size]) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); + for (size_t i = 0; i < Size; ++i) + inner_handler::extract (Stream, Value [i]); } - void getFloats(std::vector &vec, size_t size) +}; + +template +struct NIFStream::le_handler +{ + static const bool FixedLength = true; + static const size_t EncodedLength = sizeof (backing_type); + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream & Stream, presentation_type & Value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); + BOOST_STATIC_ASSERT_MSG(sizeof (presentation_type) == sizeof (backing_type), "Invalid use of NIFile::le_handler template"); + + union { + + backing_type Backing; + presentation_type Presentation; + + } u; + + u.Backing = Stream.read_le (); + + Value = u.Presentation; } - void getVector2s(std::vector &vec, size_t size) +}; + +template +struct NIFStream::conversion_handler +{ + typedef handler store_handler; + + static const bool FixedLength = store_handler::FixedLength; + static const size_t EncodedLength = store_handler::EncodedLength; + static const bool FileCompatibleLayout = false; + + static void extract (NIFStream & Stream, final_type & Value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + store_type StoreValue; + store_handler::extract (Stream, StoreValue); + Value = final_type (StoreValue); } - void getVector3s(std::vector &vec, size_t size) +}; + +template +struct NIFStream::conversion_handler +{ + typedef handler store_handler; + + static const bool FixedLength = store_handler::FixedLength; + static const size_t EncodedLength = store_handler::EncodedLength; + static const bool FileCompatibleLayout = store_handler::FileCompatibleLayout; + + static void extract (NIFStream & Stream, final_type & FinalValue) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + store_handler::extract (Stream, reinterpret_cast (FinalValue)); } - void getVector4s(std::vector &vec, size_t size) +}; + +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; + +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; + +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; + +template <> struct NIFStream::handler +{ + static const bool FixedLength = true; + static const size_t EncodedLength = + handler ::EncodedLength + + handler ::EncodedLength + + handler ::EncodedLength; + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream & stream, Transformation & value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); - } - void getQuaternions(std::vector &quat, size_t size) - { - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); + stream.uncheckedRead (value.pos); + stream.uncheckedRead (value.rotation); + stream.uncheckedRead (value.scale); } }; From e7665582ad9b855522b37d955997df527254a01d Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 22:51:06 -0800 Subject: [PATCH 1173/1483] reworked Nif::KeyListT into Nif::CurveT Renamed Nif:KeyListT to Nif::CurveT, moved it into its own file and changed its implementation so that on compatible platforms, the entire array of key-frames can be read in a single read call. Added a helper class called Nif::CurveT::interpolator to allow other code to easily evaluate the curve. Reworked part of the skeletonLoader code to use the interpolator to simplify its own logic. --- components/nif/curve.hpp | 424 +++++++++++++++++++++++++++ components/nif/data.hpp | 17 +- components/nif/niffile.hpp | 76 ----- components/nifogre/ogrenifloader.cpp | 113 ++----- components/nifogre/skeleton.cpp | 107 ++----- 5 files changed, 481 insertions(+), 256 deletions(-) create mode 100644 components/nif/curve.hpp diff --git a/components/nif/curve.hpp b/components/nif/curve.hpp new file mode 100644 index 0000000000..9a71f0923d --- /dev/null +++ b/components/nif/curve.hpp @@ -0,0 +1,424 @@ +#ifndef _NIF_KEYLIST_H_ +#define _NIF_KEYLIST_H_ + +#include + +namespace Nif +{ + +template +void bubble_sort (iterator begin, iterator end, predicate const & in_order) +{ + if (end > begin) + { + for (iterator i = begin; i != end - 1; ++i) + { + if (in_order (*(i+0), *(i+1))) + continue; + + for (iterator j = i; j >= begin; --j) + { + std::swap (*(j+0), *(j+1)); + + if (in_order (*(j+0), *(j+1))) + break; + } + } + } +} + +template +value_type linear_interpolate (float amount, value_type prev, value_type next) +{ + return prev + (next - prev) * amount; +} + +inline +Ogre::Quaternion linear_interpolate (float amount, Ogre::Quaternion prev, Ogre::Quaternion next) +{ + return Ogre::Quaternion::nlerp (amount, prev, next); +} + +template +struct KeyT { + + static const size_t EncodedLength = + NIFStream::handler ::EncodedLength + + NIFStream::handler ::EncodedLength + ; + + float mTime; + value_type mValue; + + void extract (NIFStream &nif) + { + nif.uncheckedRead (mTime); + nif.uncheckedRead (mValue); + } + + static bool in_order (KeyT const & l, KeyT const & r) + { + return l.mTime < r.mTime; + } + + template + struct NIFStream_handler + { + static const bool FixedLength = true; + static const size_t EncodedLength = derived_type::EncodedLength; + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream& Stream, KeyT & Value) + { + static_cast (Value).extract (Stream); + } + }; +}; + +template +struct LinearKeyT : KeyT +{ + static T interpolate (LinearKeyT * prev, LinearKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } +}; + +template +struct QuadraticKeyT : KeyT +{ + static const size_t EncodedLength = + KeyT ::EncodedLength + + NIFStream::handler ::EncodedLength * 2 + ; + + T mForwardValue; + T mBackwardValue; + + static T interpolate (QuadraticKeyT * prev, QuadraticKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } + + void extract (NIFStream &nif) + { + KeyT::extract (nif); + + nif.uncheckedRead (mForwardValue); + nif.uncheckedRead (mBackwardValue); + } +}; + +template +struct TbcKeyT : KeyT +{ + static const size_t EncodedLength = + KeyT ::EncodedLength + + NIFStream::handler ::EncodedLength * 3 + ; + + float mTension; + float mBias; + float mContinuity; + + static T interpolate (TbcKeyT * prev, TbcKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } + + void extract (NIFStream &nif) + { + KeyT::extract (nif); + + nif.uncheckedRead (mTension); + nif.uncheckedRead (mBias); + nif.uncheckedRead (mContinuity); + } +}; + +// register NIFStream extraction handlers for KeyT derivatives +template struct NIFStream::handler < LinearKeyT > : KeyT ::template NIFStream_handler < LinearKeyT > {}; +template struct NIFStream::handler < QuadraticKeyT > : KeyT ::template NIFStream_handler < QuadraticKeyT > {}; +template struct NIFStream::handler < TbcKeyT > : KeyT ::template NIFStream_handler < TbcKeyT > {}; + +struct Curve +{ + static const int sLinearInterpolation = 1; + static const int sQuadraticInterpolation = 2; + static const int sTBCInterpolation = 3; +}; + +template +struct CurveT : Curve { + + typedef KeyT BaseKey; + typedef TbcKeyT TcbKey; + typedef LinearKeyT LinearKey; + typedef QuadraticKeyT QuadraticKey; + + union keys { + LinearKey* Linear; + QuadraticKey* Quadratic; + TcbKey* Tcb; + }; + + class interpolator; + + int mInterpolationType; + size_t mSize; + keys mKeys; + + value_type sample (float time) const; + + KeyT const * const & keyAtIndex (size_t Index) const + { + switch (mInterpolationType) + { + case sLinearInterpolation: return mKeys.Linear + Index; + case sQuadraticInterpolation: return mKeys.Quadratic + Index; + case sTBCInterpolation: return mKeys.Tcb + Index; + } + } + + void read(NIFStream *nif, bool force=false) + { + size_t count = nif->getInt(); + + mSize = 0; + + if(count > 0 || force) + { + mInterpolationType = nif->getInt(); + + assert (mInterpolationType >= sLinearInterpolation && mInterpolationType <= sTBCInterpolation); + + if (count > 0) + { + if(mInterpolationType == sLinearInterpolation) + read_keys (nif, mKeys.Linear, count); + else if(mInterpolationType == sQuadraticInterpolation) + read_keys (nif, mKeys.Quadratic, count); + else if(mInterpolationType == sTBCInterpolation) + read_keys (nif, mKeys.Tcb, count); + else + nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + } + } + else + mInterpolationType = sLinearInterpolation; + } + + CurveT () { init (); } + CurveT (CurveT const & k) { init (k); } + //CurveT (CurveT && k) { init (); swap (std::move (k)); } + ~CurveT () { dest (); } + + operator bool () const { return mSize > 0; } + + //void operator = (CurveT && k) { swap(k); } + void operator = (CurveT const & k) { dest (); init (k); } + + void swap (CurveT & k) + { + std::swap (mSize, k.mSize); + std::swap (mInterpolationType, k.mInterpolationType); + std::swap (mKeys, k.mKeys); + } + +private: + + void init () + { + mSize = 0; + } + + void init (CurveT const & k) + { + mInterpolationType = k.mInterpolationType; + switch (mInterpolationType) + { + default: + case sLinearInterpolation: + mKeys.Linear = new LinearKey [k.mSize]; + memcpy (mKeys.Linear, k.mKeys.Linear, sizeof (LinearKey) * k.mSize); + mSize = k.mSize; + break; + case sQuadraticInterpolation: + mKeys.Quadratic = new QuadraticKey [k.mSize]; + memcpy (mKeys.Quadratic, k.mKeys.Quadratic, sizeof (QuadraticKey) * k.mSize); + mSize = k.mSize; + break; + case sTBCInterpolation: + mKeys.Tcb = new TcbKey [k.mSize]; + memcpy (mKeys.Tcb, k.mKeys.Tcb, sizeof (TcbKey) * k.mSize); + mSize = k.mSize; + break; + } + } + + void dest () + { + if (mSize > 0) + { + switch (mInterpolationType) + { + case sLinearInterpolation: delete mKeys.Linear; break; + case sQuadraticInterpolation: delete mKeys.Quadratic; break; + case sTBCInterpolation: delete mKeys.Tcb; break; + } + } + } + + template + void read_keys (NIFStream *nif, T * & store, size_t count) + { + store = new T [count]; + + mSize = count; + + nif->getArray (store, count); + + //NOTE: Is this really necessary? It seems reasonable to assume that + // animation data is already sorted by time... + // verified no out of order frames in GOTY edition + bubble_sort (store, store+count, T::in_order); + } +}; + +template +class CurveT::interpolator +{ + template + struct impl + { + key_type *Cur, *End; + + void init (key_type * Beg, size_t Len) + { + if (Len > 0) + { + Cur = Beg; + End = Beg + Len - 1; + } + else + { + Cur = End = NULL; + } + } + + bool hasData () const + { + return Cur && Cur <= End; + } + + value_type valueAt (float time) + { + while ((Cur < End) && (time >= Cur [1].mTime)) + ++Cur; + + if (Cur < End) + { + if (time > Cur->mTime) + { + key_type * Nxt = Cur + 1; + + float offset = time - Cur->mTime; + float length = Nxt->mTime - Cur->mTime; + + return key_type::interpolate (Cur, Nxt, offset / length); + } + else + return Cur->mValue; + } + else + return End->mValue; + } + + float curTime () const + { + return (Cur != NULL) ? Cur->Time : FLT_MIN; + } + + float nextTime () const + { + return Cur < End ? (Cur + 1)->mTime : FLT_MAX; + } + }; + +public: + + int mInterpolationType; + union { + impl Linear; + impl Quadratic; + impl Tcb; + }; + + interpolator (CurveT const & Curve) + { + mInterpolationType = Curve.mInterpolationType; + + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: Linear .init (Curve.mKeys.Linear, Curve.mSize); break; + case Curve::sQuadraticInterpolation: Quadratic.init (Curve.mKeys.Quadratic, Curve.mSize); break; + case Curve::sTBCInterpolation: Tcb .init (Curve.mKeys.Tcb, Curve.mSize); break; + } + } + + // return true if there is any value(s) in this curve + float hasData () const + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .hasData (); + case Curve::sQuadraticInterpolation: return Quadratic.hasData (); + case Curve::sTBCInterpolation: return Tcb .hasData (); + } + } + + // return the timestamp of the next key-frame, or FLT_MAX if + // there are no more key-frames, valid if hasData returns false + float nextTime () const + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .nextTime (); + case Curve::sQuadraticInterpolation: return Quadratic.nextTime (); + case Curve::sTBCInterpolation: return Tcb .nextTime (); + } + } + + // return the value of the curve at the specified time + // the passed in time should never exceed the result of + // nextTime, not valid if hasData returns false + value_type valueAt (float time) + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .valueAt (time); + case Curve::sQuadraticInterpolation: return Quadratic.valueAt (time); + case Curve::sTBCInterpolation: return Tcb .valueAt (time); + } + } +}; + +template +value_type CurveT::sample (float time) const +{ + interpolator i (*this); + return i.valueAt (time); +} + +typedef CurveT FloatCurve; +typedef CurveT Vector3Curve; +typedef CurveT Vector4Curve; +typedef CurveT QuaternionCurve; + +} + +#endif diff --git a/components/nif/data.hpp b/components/nif/data.hpp index f1f34184ba..d46f99abbc 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -25,6 +25,7 @@ #define OPENMW_COMPONENTS_NIF_DATA_HPP #include "controlled.hpp" +#include "curve.hpp" #include #include @@ -211,7 +212,7 @@ public: class NiPosData : public Record { public: - Vector3KeyList mKeyList; + Vector3Curve mKeyList; void read(NIFStream *nif) { @@ -222,7 +223,7 @@ public: class NiUVData : public Record { public: - FloatKeyList mKeyList[4]; + FloatCurve mKeyList[4]; void read(NIFStream *nif) { @@ -234,7 +235,7 @@ public: class NiFloatData : public Record { public: - FloatKeyList mKeyList; + FloatCurve mKeyList; void read(NIFStream *nif) { @@ -284,7 +285,7 @@ public: class NiColorData : public Record { public: - Vector4KeyList mKeyList; + Vector4Curve mKeyList; void read(NIFStream *nif) { @@ -389,7 +390,7 @@ public: struct NiMorphData : public Record { struct MorphData { - FloatKeyList mData; + FloatCurve mData; std::vector mVertices; }; std::vector mMorphs; @@ -412,9 +413,9 @@ struct NiMorphData : public Record struct NiKeyframeData : public Record { - QuaternionKeyList mRotations; - Vector3KeyList mTranslations; - FloatKeyList mScales; + QuaternionCurve mRotations; + Vector3Curve mTranslations; + FloatCurve mScales; void read(NIFStream *nif) { diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 6e629772e6..83cc6ac8fd 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -132,81 +132,5 @@ public: size_t numRoots() { return roots.size(); } }; - -template -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 Vector4Key; -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(NIFStream *nif, bool force=false) - { - size_t count = nif->getInt(); - if(count == 0 && !force) - 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->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); - } -}; -typedef KeyListT FloatKeyList; -typedef KeyListT Vector3KeyList; -typedef KeyListT Vector4KeyList; -typedef KeyListT QuaternionKeyList; - } // Namespace #endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a26f431311..f381dc239f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -166,9 +166,9 @@ public: class Value : public NodeTargetValue { private: - Nif::QuaternionKeyList mRotations; - Nif::Vector3KeyList mTranslations; - Nif::FloatKeyList mScales; + Nif::QuaternionCurve mRotations; + Nif::Vector3Curve mTranslations; + Nif::FloatCurve mScales; public: Value(Ogre::Node *target, const Nif::NiKeyframeData *data) @@ -186,68 +186,16 @@ public: virtual void setValue(Ogre::Real time) { - if(mRotations.mKeys.size() > 0) - { - if(time <= mRotations.mKeys.front().mTime) - mNode->setOrientation(mRotations.mKeys.front().mValue); - else if(time >= mRotations.mKeys.back().mTime) - mNode->setOrientation(mRotations.mKeys.back().mValue); - else - { - Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); - for(;iter != mRotations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; + if(mRotations) + mNode->setOrientation(mRotations.sample (time)); - Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); - break; - } - } - } - if(mTranslations.mKeys.size() > 0) - { - if(time <= mTranslations.mKeys.front().mTime) - mNode->setPosition(mTranslations.mKeys.front().mValue); - else if(time >= mTranslations.mKeys.back().mTime) - mNode->setPosition(mTranslations.mKeys.back().mValue); - else - { - Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); - for(;iter != mTranslations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; + if(mTranslations) + mNode->setPosition(mTranslations.sample (time)); - Nif::Vector3KeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); - break; - } - } - } - if(mScales.mKeys.size() > 0) + if(mScales) { - if(time <= mScales.mKeys.front().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); - else if(time >= mScales.mKeys.back().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); - else - { - Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); - for(;iter != mScales.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); - break; - } - } + float s = mScales.sample (time); + mNode->setScale(s, s, s); } } }; @@ -262,30 +210,14 @@ public: { private: Ogre::MaterialPtr mMaterial; - Nif::FloatKeyList mUTrans; - Nif::FloatKeyList mVTrans; - Nif::FloatKeyList mUScale; - Nif::FloatKeyList mVScale; + Nif::FloatCurve mUTrans; + Nif::FloatCurve mVTrans; + Nif::FloatCurve mUScale; + Nif::FloatCurve mVScale; - static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) + static float lookupValue(const Nif::FloatCurve &keys, float time, float def) { - if(keys.mKeys.size() == 0) - return def; - - if(time <= keys.mKeys.front().mTime) - return keys.mKeys.front().mValue; - - Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()+1); - for(;iter != keys.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - return last->mValue + ((iter->mValue - last->mValue)*a); - } - return keys.mKeys.back().mValue; + return keys ? keys.sample (time) : def; } public: @@ -392,18 +324,19 @@ class NIFObjectLoader const Nif::NiColorData *clrdata = cl->data.getPtr(); Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator"); - size_t num_colors = std::min(6, clrdata->mKeyList.mKeys.size()); + size_t num_colors = std::min(6, clrdata->mKeyList.mSize); for(size_t i = 0;i < num_colors;i++) { + Nif::Vector4Curve::BaseKey const * Key = clrdata->mKeyList.keyAtIndex (i); Ogre::ColourValue color; - color.r = clrdata->mKeyList.mKeys[i].mValue[0]; - color.g = clrdata->mKeyList.mKeys[i].mValue[1]; - color.b = clrdata->mKeyList.mKeys[i].mValue[2]; - color.a = clrdata->mKeyList.mKeys[i].mValue[3]; + color.r = Key->mValue[0]; + color.g = Key->mValue[1]; + color.b = Key->mValue[2]; + color.a = Key->mValue[3]; affector->setParameter("colour"+Ogre::StringConverter::toString(i), Ogre::StringConverter::toString(color)); affector->setParameter("time"+Ogre::StringConverter::toString(i), - Ogre::StringConverter::toString(clrdata->mKeyList.mKeys[i].mTime)); + Ogre::StringConverter::toString(Key->mTime)); } } else if(e->recType == Nif::RC_NiParticleRotation) diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index e97e91ef03..66060b9676 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -10,6 +10,11 @@ namespace NifOgre { +template +static value_type min (value_type V0, value_type V1, value_type V2, value_type V3) +{ + return std::min (std::min (V0, V1), std::min (V2, V3)); +} void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { @@ -22,15 +27,6 @@ void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string & continue; const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - Ogre::Bone *bone = skel->getBone(targets[i]); // NOTE: For some reason, Ogre doesn't like the node track ID being different from // the bone ID @@ -38,83 +34,30 @@ void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string & anim->getNodeTrack(bone->getHandle()) : anim->createNodeTrack(bone->getHandle(), bone); - 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 = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); + Nif::QuaternionCurve::interpolator rci (kf->mRotations); + Nif::Vector3Curve::interpolator tci (kf->mTranslations); + Nif::FloatCurve::interpolator sci (kf->mScales); - bool didlast = false; - while(!didlast) + float next_timestamp = startTime; + + for (;;) { - float curtime = std::numeric_limits::max(); - - //Get latest time - 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, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } + static const Ogre::Vector3 one (1,1,1); Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::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 - { - Nif::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 - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } + kframe = nodetrack->createNodeKeyFrame (next_timestamp); + + if (rci.hasData ()) kframe->setRotation (rci.valueAt (next_timestamp)); + if (tci.hasData ()) kframe->setTranslate (tci.valueAt (next_timestamp)); + if (sci.hasData ()) kframe->setScale (sci.valueAt (next_timestamp)*one); + + if (next_timestamp >= stopTime) + break; + + next_timestamp = min (stopTime, + rci.nextTime (), + tci.nextTime (), + sci.nextTime ()); } } anim->optimise(); From 6dbb53493b34c6430e8bdf0ea0d4f411facfa1b5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 3 Jan 2013 23:39:00 -0800 Subject: [PATCH 1174/1483] enable move construction/assignment to key ESM data structure to reduce sorting costs --- components/esm/defs.hpp | 10 +++++++ components/esm/loaddial.hpp | 36 ++++++++++++++++++++++ components/esm/loadinfo.hpp | 60 +++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index bd86f9ba03..3dc498a639 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -1,6 +1,16 @@ #ifndef OPENMW_ESM_DEFS_H #define OPENMW_ESM_DEFS_H +#if _MSC_VER >= 1600 +#define OPENMW_ESM_ENABLE_CPP11_MOVE +#define OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(Class) \ + Class () {} \ + Class (Class const & that) { copy (*this, that); } \ + Class (Class && that) { move (*this, that); } \ + Class & operator = (Class const & that) { copy (*this, that); return *this; } \ + Class & operator = (Class && that) { move (*this, that); return *this; } +#endif + #include namespace ESM diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 61f3f763de..bb726b8557 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "loadinfo.hpp" @@ -35,6 +36,41 @@ struct Dialogue void load(ESMReader &esm); void save(ESMWriter &esm); + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(Dialogue) + + static void copy (Dialogue & d, Dialogue const & s) + { + d.mId = s.mId; + d.mType = s.mType; + d.mInfo = s.mInfo; + } + static void move (Dialogue & d, Dialogue & s) + { + d.mId = std::move (s.mId); + d.mType = std::move (s.mType); + d.mInfo = std::move (s.mInfo); + } +#endif }; } + +/* + custom swap to prevent memory allocations and deallocations for mId and mInfo + while sorting +*/ +namespace std +{ + template <> inline + void swap (ESM::Dialogue & Left, ESM::Dialogue & Right) + { +#define _swp(id) std::swap (Left.id, Right.id); + _swp(mId); + _swp(mType); + _swp(mInfo); +#undef _swp + } +} + #endif diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 2361ed9eb5..c7608ca866 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -43,6 +43,22 @@ struct DialInfo { std::string mSelectRule; // This has a complicated format Variant mValue; + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(SelectStruct) + + static void copy (SelectStruct & d, SelectStruct const & s) + { + d.mSelectRule = s.mSelectRule; + d.mValue = s.mValue; + } + + static void move (SelectStruct & d, SelectStruct & s) + { + d.mSelectRule = std::move (s.mSelectRule); + d.mValue = std::move (s.mValue); + } +#endif // OPENMW_ESM_ENABLE_CPP11_MOVE }; // Journal quest indices (introduced with the quest system in Tribunal) @@ -100,6 +116,50 @@ struct DialInfo void load(ESMReader &esm); void save(ESMWriter &esm); + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(DialInfo) + + static void copy (DialInfo & d, DialInfo const & s) + { + d.mData = s.mData; + d.mSelects = s.mSelects; + d.mId = s.mId; + d.mPrev = s.mPrev; + d.mNext = s.mNext; + d.mActor = s.mActor; + d.mRace = s.mRace; + d.mClass = s.mClass; + d.mNpcFaction = s.mNpcFaction; + d.mPcFaction = s.mPcFaction; + d.mCell = s.mCell; + d.mSound = s.mSound; + d.mResponse = s.mResponse; + d.mResultScript = s.mResultScript; + d.mFactionLess = s.mFactionLess; + d.mQuestStatus = s.mQuestStatus; + } + + static void move (DialInfo & d, DialInfo & s) + { + d.mData = std::move (s.mData); + d.mSelects = std::move (s.mSelects); + d.mId = std::move (s.mId); + d.mPrev = std::move (s.mPrev); + d.mNext = std::move (s.mNext); + d.mActor = std::move (s.mActor); + d.mRace = std::move (s.mRace); + d.mClass = std::move (s.mClass); + d.mNpcFaction = std::move (s.mNpcFaction); + d.mPcFaction = std::move (s.mPcFaction); + d.mCell = std::move (s.mCell); + d.mSound = std::move (s.mSound); + d.mResponse = std::move (s.mResponse); + d.mResultScript = std::move (s.mResultScript); + d.mFactionLess = std::move (s.mFactionLess); + d.mQuestStatus = std::move (s.mQuestStatus); + } +#endif // OPENMW_ESM_ENABLE_CPP11_MOVE }; } From 8dad04eef19e7471787615348181d6c32ed6e82a Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 13 Jan 2013 13:03:11 -0800 Subject: [PATCH 1175/1483] hid JournalWindow behind IJournalWindow interface, and put its entire implementation, class definition and all, into journalwindow.cpp --- apps/openmw/mwgui/journalwindow.cpp | 223 ++++++++++++++----------- apps/openmw/mwgui/journalwindow.hpp | 34 +--- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +- 4 files changed, 137 insertions(+), 126 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 23588a4afa..9540e69868 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -5,6 +5,16 @@ #include "../mwbase/journal.hpp" #include "../mwbase/soundmanager.hpp" +#include +#include +#include +#include + +#include "windowbase.hpp" +#include "imagebutton.hpp" + +using namespace MWGui; + namespace { struct book @@ -77,116 +87,135 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) //std::string } - -MWGui::JournalWindow::JournalWindow () - : WindowBase("openmw_journal.layout") - , mPageNumber(0) +namespace { - mMainWidget->setVisible(false); - //setCoord(0,0,498, 342); - center(); - - getWidget(mLeftTextWidget, "LeftText"); - getWidget(mRightTextWidget, "RightText"); - getWidget(mPrevBtn, "PrevPageBTN"); - mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyPrevPage); - getWidget(mNextBtn, "NextPageBTN"); - mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyNextPage); - //MyGUI::ItemBox* list = new MyGUI::ItemBox(); - //list->addItem("qaq","aqzazaz"); - //mScrollerWidget->addChildItem(list); - //mScrollerWidget->addItem("dserzt",MyGUI::UString("fedgdfg")); - //mEditWidget->addText("ljblsxdvdsfvgedfvdfvdkjfghldfjgn sdv,nhsxl;vvn lklksbvlksb lbsdflkbdSLKJGBLskdhbvlshow(); - //mEditWidget->setEditStatic(true); - mLeftTextWidget->addText("left texxxt "); - mLeftTextWidget->setEditReadOnly(true); - mRightTextWidget->setEditReadOnly(true); - mRightTextWidget->setEditStatic(true); - mLeftTextWidget->setEditStatic(true); - mRightTextWidget->addText("Right texxt "); - - //std::list list = formatText("OpenMW rgh dsfg sqef srg ZT uzql n ZLIEHRF LQSJH GLOIjf qjfmj hslkdgn jlkdjhg qlr isgli shli uhs fiuh qksf cg ksjnf lkqsnbf ksbf sbfkl zbf kuyzflkj sbgdfkj zlfh ozhjfmo hzmfh lizuf rty qzt ezy tkyEZT RYYJ DG fgh is an open-source implementation of the game engine found in the game Morrowind. This is a dumb test text msodjbg smojg smoig fiiinnn"); - //std::list list = formatText(); - //displayLeftText(list.front()); -} - -void MWGui::JournalWindow::open() -{ - mPageNumber = 0; - if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) + struct JournalWindow : WindowBase, IJournalWindow { - book journal; - journal.endLine = 0; + MyGUI::EditPtr mLeftTextWidget; + MyGUI::EditPtr mRightTextWidget; + MWGui::ImageButton* mPrevBtn; + MWGui::ImageButton* mNextBtn; + std::vector mLeftPages; + std::vector mRightPages; + int mPageNumber; //store the number of the current left page - for(std::deque::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();++it) + JournalWindow () + : WindowBase("openmw_journal.layout") + , mPageNumber(0) { - std::string a = it->getText(MWBase::Environment::get().getWorld()->getStore()); - journal = formatText(a,journal,10,17); - journal.endLine = journal.endLine +1; - journal.pages.back() = journal.pages.back() + std::string("\n"); + mMainWidget->setVisible(false); + //setCoord(0,0,498, 342); + center(); + + getWidget(mLeftTextWidget, "LeftText"); + getWidget(mRightTextWidget, "RightText"); + getWidget(mPrevBtn, "PrevPageBTN"); + mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&JournalWindow::notifyPrevPage); + getWidget(mNextBtn, "NextPageBTN"); + mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&JournalWindow::notifyNextPage); + + + + mLeftTextWidget->setEditReadOnly(true); + mRightTextWidget->setEditReadOnly(true); + mRightTextWidget->setEditStatic(true); + mLeftTextWidget->setEditStatic(true); } - //std::string a = MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); - //std::list journal = formatText(a,10,20,1); - bool left = true; - for(std::list::iterator it = journal.pages.begin(); it != journal.pages.end();++it) + + void close() { - if(left) + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + } + + void open() + { + mPageNumber = 0; + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) { - mLeftPages.push_back(*it); + book journal; + journal.endLine = 0; + + for(std::deque::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();++it) + { + std::string a = it->getText(MWBase::Environment::get().getWorld()->getStore()); + journal = formatText(a,journal,10,17); + journal.endLine = journal.endLine +1; + journal.pages.back() = journal.pages.back() + std::string("\n"); + } + //std::string a = MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); + //std::list journal = formatText(a,10,20,1); + bool left = true; + for(std::list::iterator it = journal.pages.begin(); it != journal.pages.end();++it) + { + if(left) + { + mLeftPages.push_back(*it); + } + else + { + mRightPages.push_back(*it); + } + left = !left; + } + if(!left) mRightPages.push_back(""); + + mPageNumber = mLeftPages.size()-1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } else { - mRightPages.push_back(*it); + //std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); } - left = !left; } - if(!left) mRightPages.push_back(""); - mPageNumber = mLeftPages.size()-1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); + void setVisible (bool newValue) + { + WindowBase::setVisible (newValue); + } - } - else - { - //std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); - } + + void displayLeftText(std::string text) + { + mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength()); + mLeftTextWidget->addText(text); + } + + void displayRightText(std::string text) + { + mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength()); + mRightTextWidget->addText(text); + } + + + + void notifyNextPage(MyGUI::Widget* _sender) + { + if(mPageNumber < int(mLeftPages.size())-1) + { + std::string nextSound = "book page2"; + MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); + mPageNumber = mPageNumber + 1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } + } + + void notifyPrevPage(MyGUI::Widget* _sender) + { + if(mPageNumber > 0) + { + std::string prevSound = "book page"; + MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0); + mPageNumber = mPageNumber - 1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } + } + }; } -void MWGui::JournalWindow::displayLeftText(std::string text) -{ - mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength()); - mLeftTextWidget->addText(text); -} - -void MWGui::JournalWindow::displayRightText(std::string text) -{ - mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength()); - mRightTextWidget->addText(text); -} - - -void MWGui::JournalWindow::notifyNextPage(MyGUI::Widget* _sender) -{ - if(mPageNumber < int(mLeftPages.size())-1) - { - std::string nextSound = "book page2"; - MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); - mPageNumber = mPageNumber + 1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); - } -} - -void MWGui::JournalWindow::notifyPrevPage(MyGUI::Widget* _sender) -{ - if(mPageNumber > 0) - { - std::string prevSound = "book page"; - MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0); - mPageNumber = mPageNumber - 1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); - } -} +// glue the implementation to the interface +IJournalWindow * MWGui::IJournalWindow::create () { return new JournalWindow (); } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 27bf608e18..8f734dc244 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,39 +1,21 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H -#include - -#include "windowbase.hpp" -#include "imagebutton.hpp" +namespace MWBase { class WindowManager; } namespace MWGui { - class JournalWindow : public WindowBase + struct IJournalWindow { - public: - JournalWindow(); - virtual void open(); + /// construct a new instance of the one JournalWindow implementation + static IJournalWindow * create (); - private: - void displayLeftText(std::string text); - void displayRightText(std::string text); + /// destroy this instance of the JournalWindow implementation + virtual ~IJournalWindow () {}; - - /** - *Called when next/prev button is used. - */ - void notifyNextPage(MyGUI::Widget* _sender); - void notifyPrevPage(MyGUI::Widget* _sender); - - MyGUI::EditBox* mLeftTextWidget; - MyGUI::EditBox* mRightTextWidget; - MWGui::ImageButton* mPrevBtn; - MWGui::ImageButton* mNextBtn; - std::vector mLeftPages; - std::vector mRightPages; - int mPageNumber; //store the number of the current left page + /// show/hide the journal window + virtual void setVisible (bool newValue) = 0; }; - } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2171beaffb..6b38042a67 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -145,7 +145,7 @@ namespace MWGui mMap = new MapWindow(cacheDir); mStatsWindow = new StatsWindow(); mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(); + mJournal = IJournalWindow::create(); mMessageBoxManager = new MessageBoxManager(); mInventoryWindow = new InventoryWindow(mDragAndDrop); mTradeWindow = new TradeWindow(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 652ad870f3..43951d46a8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -51,7 +51,7 @@ namespace MWGui class MainMenu; class StatsWindow; class InventoryWindow; - class JournalWindow; + class IJournalWindow; class CharacterCreation; class DragAndDrop; class ToolTips; @@ -253,7 +253,7 @@ namespace MWGui StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; - JournalWindow* mJournal; + IJournalWindow* mJournal; DialogueWindow *mDialogueWindow; ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; From 85595245abb777dc038785a42afbb3781e570238 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 01:00:11 -0800 Subject: [PATCH 1176/1483] Updated journal layout to match Bethesda's version more closely --- files/mygui/openmw_journal.layout | 94 +++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index fdf82e4dee..addd4296d7 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -2,24 +2,84 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 75757cb675f91b3e010221cb9687842c70f89009 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 10:43:41 -0800 Subject: [PATCH 1177/1483] Created a class to represent a stream of UTF8 characters. --- components/misc/utf8stream.hpp | 115 +++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 components/misc/utf8stream.hpp diff --git a/components/misc/utf8stream.hpp b/components/misc/utf8stream.hpp new file mode 100644 index 0000000000..a491ed0824 --- /dev/null +++ b/components/misc/utf8stream.hpp @@ -0,0 +1,115 @@ +#ifndef MISC_UTF8ITER_HPP +#define MISC_UTF8ITER_HPP + +#include + +class utf8_stream +{ +public: + + typedef uint32_t unicode_char; + typedef unsigned char const * point; + + static const unicode_char sBadChar = 0xFFFFFFFF; + + utf8_stream (point begin, point end) : + cur (begin), nxt (begin), end (end) + { + } + + utf8_stream (std::pair range) : + cur (range.first), nxt (range.first), end (range.second) + { + } + + bool eof () const + { + return cur == end; + } + + point current () const + { + return cur; + } + + unicode_char peek () + { + if (cur == nxt) + next (); + return val; + } + + unicode_char consume () + { + if (cur == nxt) + next (); + cur = nxt; + return val; + } + + static std::pair decode (point cur, point end) + { + if ((*cur & 0x80) == 0) + { + unicode_char chr = *cur++; + + return std::make_pair (chr, cur); + } + + int octets; + unicode_char chr; + + boost::tie (octets, chr) = octet_count (*cur++); + + if (octets > 5) + return std::make_pair (sBadChar, cur); + + auto eoc = cur + octets; + + if (eoc > end) + return std::make_pair (sBadChar, cur); + + while (cur != eoc) + { + if ((*cur & 0xC0) != 0x80) // check continuation mark + return std::make_pair (sBadChar, cur);; + + chr = (chr << 6) | unicode_char ((*cur++) & 0x3F); + } + + return std::make_pair (chr, cur); + } + +private: + + static std::pair octet_count (unsigned char octet) + { + int octets; + + unsigned char mark = 0xC0; + unsigned char mask = 0xE0; + + for (octets = 1; octets <= 5; ++octets) + { + if ((octet & mask) == mark) + break; + + mark = (mark >> 1) | 0x80; + mask = (mask >> 1) | 0x80; + } + + return std::make_pair (octets, octet & ~mask); + } + + void next () + { + boost::tie (val, nxt) = decode (nxt, end); + } + + point cur; + point nxt; + point end; + unicode_char val; +}; + +#endif \ No newline at end of file From 55ca037411de9f669da282c1c86203862e74b029 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 11:56:00 -0800 Subject: [PATCH 1178/1483] Created a MyGUI widget to present a page of formatted text. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/bookpage.cpp | 1204 ++++++++++++++++++++++++ apps/openmw/mwgui/bookpage.hpp | 120 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 4 files changed, 1327 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwgui/bookpage.cpp create mode 100644 apps/openmw/mwgui/bookpage.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f4fdcb390e..fcd2c14500 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair repair soulgemdialog companionwindow + merchantrepair repair soulgemdialog companionwindow bookpage ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp new file mode 100644 index 0000000000..4007dc1f19 --- /dev/null +++ b/apps/openmw/mwgui/bookpage.cpp @@ -0,0 +1,1204 @@ +#include "bookpage.hpp" + +#include "MyGUI_FontManager.h" +#include "MyGUI_RenderItem.h" +#include "MyGUI_RenderManager.h" +#include "MyGUI_TextureUtility.h" +#include "MyGUI_FactoryManager.h" + +#include + +#include + +namespace MWGui +{ + struct TypesetBook; + struct PageDisplay; + struct BookPage; +} + +using namespace MyGUI; +using namespace MWGui; + +static bool ucs_space (int code_point); +static bool ucs_line_break (int code_point); +static bool ucs_breaking_space (int code_point); + +struct IBookTypesetter::IStyle { virtual ~IStyle () {} }; + +struct MWGui::TypesetBook : ITypesetBook +{ + typedef std::vector content; + typedef std::list contents; + typedef utf8_stream::point utf8_point; + typedef std::pair range; + + struct style : IBookTypesetter::IStyle + { + IFont* Font; + Colour HotColour; + Colour ActiveColour; + Colour NormalColour; + interactive_id InteractiveId; + + bool match (IFont* tstFont, Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return (Font == tstFont) && + partal_match (tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId); + } + + bool match (char const * tstFont, Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return (Font->getResourceName () == tstFont) && + partal_match (tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId); + } + + bool partal_match (Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return + (HotColour == tstHotColour ) && + (ActiveColour == tstActiveColour ) && + (NormalColour == tstNormalColour ) && + (InteractiveId == tstInteractiveId ) ; + } + }; + + typedef std::list